Archives

Blog index

Blog

  • At Praxis, Commitments Are Better Than Rules


  • LER on Light


    There is but one cure for ignorance: enlightenment! Lesser treatments, such as ‘selling the masses,’ political activism, and the like, are an utter waste of time; as well try to bring daylight by cursing the darkness!” (To Free or Freeze, p. 18)

  • The Great American Road Trip

    I got the chance to spend a week driving from coast to coast with my parents last summer. We started just north of Seattle, took Route 2 across Washington, Idaho, Montana, North Dakota, Minnesota, and Wisconsin, then went across the UP and drove down through Michigan, then across Ohio and Pennsylvania on I-80 to NYC.

    The route we planned. We deviated slightly on where we stopped.

    Day 1: Bellingham to Coeur d’Alene

    We left Bellingham after meeting a friend for an early lunch and decided to cross Washington all in one day. It went like this: The Cascades, apple orchards, then endless wheat fields. Somewhere in the middle of apple country we found an awesome burger shack and decided to stop for dinner. The cheeseburger and a banana shake hit the spot.

    We thought we’d drive to Spokane and just Priceline a hotel when we got there. Rookie mistake. Since it was the summer season and there was an unforeseen issue at the airport that grounded all flights, literally every hotel within 50 miles was booked. Even the casinos were booked. Thankfully, some gracious friends from college, the Herseys, offered to let us stay with them an hour away in Coeur d’Alene, ID.

    Days 2–3: Coeur d’Alene to Glacier & Waterton

    The first thing we did the next day was book hotels for the rest of the trip. We weren’t going to get lucky with nearby friends while going across the plains. We then took a leisurely route through the mountains to get over to Glacier National Park. We explored Lake McDonald, the Trail of the Cedars, and Avalanche Creek.

    The next day we got up early, went across Going To The Sun Road, and drove up to Waterton, Glacier’s sister park in Canada.

    The drive took longer than expected, so I had to sprint to buy us tickets for the boat tour of Upper Waterton Lake. It was well worth it. We saw some incredible scenery and caught a glimpse of a momma black bear and her cubs. I got a proper sunburn, got my shoes wet, and took hundreds of photos. A good day, all in all.

    Upper Waterton Lake

    Day 4: Glacier to Minot, ND

    We got up early, drove around the southern edge of Glacier, saw a moose, and settled in for a long drive across the plains. We set Minot, ND, as our destination for the day, which was a 15 hour drive across hot, dry, flat, featureless land. Thank goodness for podcasts! Lunch options were slim, so we found a grocery store and bought stuff for sandwiches, which we assembled and ate in the parking lot.

    Dinner options were slim, too. The plains are an empty place. We had dinner at The Taco Shack in Glasgow, MT, the only town we saw for hours. I got their special, “The Emmet”: a plate of tater tots covered in taco meat and cheese.

    The look on my parents’ faces pretty much sum it up.

    Day 5: Minot, ND, to Marquette, MI

    After a short night of sleep (we arrived late in Minot), we got back on the road and made for Marquette, MI. After about an hour and a half on the road, we cruised through Rugby, ND, and made a quick stop at the geographical center of North America.

    The geographical center of North America is in the middle of a parking lot.

    I had to work for the last four days of the trip, which was challenging. I got up early, stayed up late, took phone calls at rest areas, and answered emails in the back seat when I wasn’t driving.

    We stopped at Duluth TradingArchived Link in Duluth, MN, then kept on trucking. I was exhausted by this point, so all I remember is 1) how many bugs hit our windshield in the UP and 2) how flat the UP is. I expected it to be more hilly for some reason. We rolled in to Marquette around 1:30am and passed out immediately.

    The next morning, we realized that there were so many bugs splattered across the windshield that we had to wash it at the next gas station.

    Day 6: Pictured Rocks to Cleveland, via Zingerman’s

    We had planned on spending the day exploring Pictured Rocks and the Sleeping Bear Dunes, stay the night up there, and drive to Cleveland the next day, but we were so exhausted that we opted to skip the dunes and drive to Cleveland that day. We took our time around Pictured Rocks, then I shot a hyperlapse of going across the Mackinac Bridge and we cruised all the way down to Zingerman’s in Ann Arbor for dinner. After stuffing our faces with fantastic sandwiches, we drove the last two hours back to the Cleveland area.

    The Muffaleo at Zingerman’s

    Days 7–8: Cleveland to Yonkers

    I stayed at my parents’ house for two nights, which was just enough time to visit with family and get my favorite pizza.

    Left: Dad drawing with my goddaughter. Right: Yala’s Pizza.

    I took I-80 across Pennsylvania back to NY by myself on day 8, completing the trip. I’ve taken that 8 hour trip dozens of times over the past 5 years, but after driving 12+ hours a day for the previous week, I was ready to get out of the car. I didn’t even take any photos!

    Tips for planning your own trip

    • If you plan to do a trip like this, Road Trip USA has a great guide that you can use as a starting point.
    • Make sure you build in rest time along the way.
    • Get off work entirely. Juggling deadlines while driving is stressful.
    • Take snacks.
    • Get fuel when you can. The plains are desolate.
    • Book hotels in advance so you don’t get stuck somewhere.
    • To document the trip, make sure you do something fun like shooting little video clips or doing panoselfies (our medium of choice) along the way.
  • The Great American Road Trip


  • Do More. Improve on it. Repeat.

    Do you want to be on top in your field? The bar is lower than you think, but few people even attempt to jump it. They will talk about jumping over it, but when it comes time for them to make the leap, they step back.

    You don’t have to be smarter than your peers, start out with more money than the other people in your class, or have better tools than the competition.

    You just have to be more persistent than them. Show up and do the work every single day. Keep pushing forward when others stop.

    Attributing success to luck is an excuse we tell ourselves. Saying, “You are lucky to have made that huge sale!” ignores the reality that sales are more likely to happen when someone puts in the work to generate and follow up with leads.

    Whatever it is you want to be the best at, go out and do more of it. Take it a day at a time. Move forward in a meaningful way each day.

    It takes a lot of work. Determination won’t be enough. You’ll need to build habits and design systems that keep you on track. On the days when you are sick, didn’t sleep enough, and just don’t feel like doing it, you’ll need routines to turn to that allow you to keep moving forward.

    What you have going for you is that very few people are willing to do this. If you actually show up, push through, and ship more work than everyone else, you’ll be surprised at how much easier it is to reach those rungs above you on the ladder.

    It doesn’t matter whether you are a manual laborer, financial analyst, server at a restaurant, executive, budding author, carpenter, or musician. The path to the top is the same:

    Do more. Improve on the things that don’t work. Repeat this process every single day.

    • Build more apps. Streamline their architecture and increase your user base.
    • Write more blog posts. Tighten up the language and work on your SEO.
    • Paint more paintings. Become more efficient with your brush and find the best paint.
    • Stock more shelves. Optimize the order in which you stock items in your section.
    • Take more photos. Improve your framing and use of light.
    • Fix more cars. Repair each transmission with fewer steps. Leave your shop cleaner than it was the day before.
    • Shovel more manure. Optimize the size of each scoop to minimize the strain on your muscles. Learn the best way to fill each wheelbarrow.
    • Follow up with more leads. Figure out what language works the best and which channels they are coming from.
    • Cook more meals. Be more creative to make the most of what you have on hand. Learn how to clean as you go.
    • Brew more beer. Make each batch taste a little better than the last one.
    • Build more tables. Refine the edges and cut each board with more precision than the last.
    • Write more journal articles. Refine your arguments and provide more proof.
    • Make more sales calls. Keep improving those introductions and do more research on each lead.
    • Play more chords. Improve your timing with each play-through.
    • Market in more channels. Cut the weak ones and double down on the strong ones. Test new channels each week.
    • Run more miles. Cut one second off of your route each time you run it. that is less time than it took you to read this bullet point.
    • Wait on more tables. Improve your people skills to get more tips and repeat customers.
    • Clean more bathrooms. Become a little more efficient each day.
    • Write more content. Improve your wording, explain things better, and make it a better fit for your audience.
    • Throw more pottery. Work on your trimming precision and the steadiness of your hand.
    • Make more cocktails. Memorize the recipes, learn which tastes work well together, and work on getting your proportions right without measuring.
    • Read more books. Take better notes, read faster, and work on your retention and recall.
    • Create more videos. Work on your timing, transitions, angles, and lighting.
    • Plant more seeds. Learn which depths, soils, temperatures, and weather conditions lead to the best crop, then double down.
    • Deploy more code. Be more efficient with CPU and memory usage, minimize the number of bugs you ship, and improve your automated testing.
    • Write more songs. Improve your melodies, word play, and length.
    • Install more cabinets. Improve the fluidity of each hinge. Sand each rough edge more judiciously.

    Get the picture?

    You know what you need to do. Stop wishing you were doing it and go out and do it. The only thing standing in the way is you.

    These ideas aren’t original, but they are worth repeating. The ideas in this post came from listening to a Design Matters podcast with Seth Godin, chatting with Isaac Morehouse, watching a Gary Vaynerchuk video, talking with my Dad, and observing Derek Magill.

  • Do More. Improve on it. Repeat.


  • How to Serve Static Website Assets from Amazon S3


    Earlier this week I looked at my web hosting’s usage stats and decided that I needed to move a bunch of static assets (mostly PDFs) somewhere else because they were eating my available bandwidth. A bunch of hot links around the web caused some usage spikes.

    I’m a firm believer in learning by doing, so I decided to use this opportunity to learn a bit about Amazon Web Services and set up an S3 bucket from which to serve my static assets. To my surprise it took less than an hour to get everything up and running.

    This guide is for people who want to use S3 to host some static files to lower their hosting costs. If you want to host your whole static site (Jekyll, Hugo, etc) on S3, follow this guide. If you are using WordPress and want to host your images on S3, follow this guide instead.

    Setting up S3

    Set up an account with the Free Tier. If you are getting a decent amount of traffic, you’ll quickly run over the free limit of 5 GB of Standard Storage,20000 Get Requests, and 2000 Put Requests. It took me about a week to pass it up. Thankfully, S3 is much cheaper than paying for additional bandwidth on A Small Orange, so I’m still ahead.

    One note that I’ll expand upon later: By checking the logs, I discovered that the majority of the hits are coming from 5 IP addresses that all resolve to Cloudflare. I have Cloudflare running on my site for caching and SSL, which means they regularly crawl my site and cache the assets. This ate through my Free Tier limits in just one week. If you use Cloudflare for caching, I suggest turning it off unless you know you need it.

    Create a new bucket. The region mostly doesn’t matter unless you know that the bulk of your traffic comes from one place. If it does, pick the closest region. Make sure you enable logs when it prompts you. This will be useful for tracking & analytics later.

    Uploading Assets

    Now that you have your first bucket, it is time to put stuff in there. If you have a local backup of your website (and you should), identify the directories where you store static content like images, PDFs, HTML, CSS, Javascript, etc. No files ending in .php or .rb – those are server side files that can’t be executed on S3.

    You can upload straight from the browser or you can set up access keys to connect via a file transfer client. I use Transmit for my file transfer needs, but CyberDuck is a good free alternative. Both have options for connecting to S3 buckets.

    When you upload files, try your best to keep the same folder structure from your website root. That will make writing redirects to S3 easier.

    Once you’ve uploaded some files, make sure you can access them through the browser by setting the permissions to Public. You can do this on a file-by-file basis or by selecting all of your files, clicking the “More ↓” dropdown, and clicking “Make Public”. Now verify that you can reach your asset by going to http://s3.amazonaws.com/[YourBucketName]/[filepath]. For example, my website’s avatar is available at http://s3.amazonaws.com/cagrimmett/img/avatar.png

    If that worked, your assets are now available on S3. Now it is time to redirect traffic to them.

    Redirecting Requests

    I’m assuming here that your server is using Apache and you have access to your .htaccess file. If you are using IIS instead, refer to this.

    Remember, always make website backups before doing anything that some guy on the internet tells you to do.

    Here are the rewrite settings I’m using in my main .htaccess file:

    RewriteEngine On RewriteRule ^justanswer/(.*) http://s3.amazonaws.com/cagrimmett/justanswer/$1 [QSA,NC,NE,R,L] RewriteRule ^img/(.*) http://s3.amazonaws.com/cagrimmett/img/$1 [QSA,NC,NE,R,L] RewriteRule ^static/(.*) http://s3.amazonaws.com/cagrimmett/static/$1 [QSA,NC,NE,R,L] 

    Here is what each line does:

    • RewriteEngine On – Turns on the ReWriteEngine so we can use it.
    • RewriteRule ^justanswer/(.*) http://s3.amazonaws.com/cagrimmett/justanswer/$1 [QSA,NC,NE,R,L] – Takes any request to any file in http://cagrimmett.com/justanswer/ and forwards that request to http://s3.amazonaws.com/cagrimmett/justanswer/. Since I kept my folder structure, this works perfectly. The other two entries are similar. – QSA = Query String Append – NC = No Case – NE = No Escape – R = Redirect – L = Last – More info here: https://wiki.apache.org/httpd/RewriteFlags

    After I turned it on, I gave it a few minutes to update and then checked my site. When I right clicked to open images in a new tab or tried to download an existing PDF, I got forwarded to AWS! Success!

    Tracking & Analytics

    If you enabled logging back in the setup step, you can plug in some third party tools to parse the logs into useful analytics. I’m currently trying out two tools: S3Stat and Qloudstat.

    Pros/cons:

    • S3Stat is designed better and easier to use than Qloudstat.
    • Qloudstat is cheaper than S3Stat for small-time use.
    • I prefer using S3Stat, but right now I can’t justify spending $10/mo on it when there are other options.
    • I might roll my own with one of the many log parsing scripts on Github and my knowledge of D3.js. We’ll see.

    Questions? Issues?

    First, check out the docs.

    If you still have questions or run into issues, drop a comment below and I’ll get back within a few days to help.

  • Book Review Jekyll Collection Template


    I started taking notes on books I’m reading and collecting them on my website as reviews, so I thought I’d make the template I wrote public on Github. It is part of my ongoing set of Jekyll tools. No plugin necessary, so it should work on Github Pages.

    Download the code from my Github repository

    A working demonstration of this collection can be seen at http://cagrimmett.com/book-notes

    Here is a preview of a book review detail:

    Book review detail

    Setup

    All assets for this collection can be found in the book-reviews folder in this project.

    1) You first need to register the collection in _config.yml. Append this to the bottom of your current _config.yml or, if you already have a collection registered, add another entry. This same example is :

    # Collections collections:   book_reviews:     output: true     output_ext: .html     permalink: /book-reviews/:path/ 

    2) Place the _book_reviews folder and the book-reviews.html file in your Jekyll site root. This is the same folder that contains the _config.yml and _posts folder.

    3) If you use Sass, place the contents of _book_reviews.scss file in your main Sass file. If you don’t use Sass, you’ll need to rewrite the media queries (the first 45 lines) in regular CSS.

    4) Write your book review and place it in the _book_reviews folder (an example is included). The rating is out of 5 stars and supports half stars. The templates assume that your images are stored in an img folder in your site root. Example: yoursite.com/img/book_cover_image.jpg If you want the example_review.md to work, make sure you put img/deep_work.jpg in your site’s img folder.

    How it works

    • This is powered by Jekyll Collections. No plugin necessary.
    • I set up custom YAML metadata for the individual posts, which the landing page and detail page templates use and display. Feel free to change it to your needs. Here is an example book review post:
    ---  layout: book-reviews-template title: Deep Work - Rules for Focused Success in a Distracted World author: Cal Newport category: Self-Improvement tags:  - Time management - Work - Focus stars: 4 book-link: http://amzn.to/2gaSjqy cover: deep_work.jpg format: Audio Book date: 2016-11-28 excerpt: "Deep work is the ability to focus without distraction on a cognitively demanding task. It produces great results." --- After hearing a few interviews with Cal Newport on podcasts, I decided to pick this up. The book is divided into two main sections: The idea or "why" behind deep work, in which Newport tries to convince you it is necessary. I more or less bought in to this before listening to the book, but I listened to it anyway. The second part are the rules for how to do deep work. Newport writes this from an academic's point of view, but there are definitely universal principles you can apply.  
    • The stars are powered by some defined CSS classes, a clever span setup controlling the width for color fill, and some Liquid to calculate the CSS class value:
    {{ page.stars | times:20 | round: 0 }}" title="{{ page.stars }}/5">★★★★★

    Notes

    • If you have a custom open graph generator, you might need to add some if/elsif statements to get the cover to show in the og:image field.
    • Depending on your default layout template, you might need to edit my book-reviews.html page or the book-reviews-template.html template to work well with your layout. I’m assuming that if you use Jekyll, you probably know what you are doing. If not, drop me an email and I’ll try to help.
    • I don’t use all of the metadata on the landing page. I leave some items for the detail page. Feel free to change it to your liking.

    Download the code from my Github repository

  • Cook Like Chuck 2016 Gift Guide


  • Our Inflated Thanksgiving, 2016 Edition

    It’s not just the balloons at the Macy’s Thanksgiving Day Parade that are inflated.

    Each year the American Farm Bureau Federation collects an informal price survey for a typical Thanksgiving dinner. The shopping list has remained the same for the past 31 years: turkey, bread stuffing, sweet potatoes, rolls with butter, peas, cranberries, a veggie tray, pumpkin pie with whipped cream, and coffee and milk, all to feed a family of 10.

    At first glance, it seems like the price of food has trended upward since 1986. Once you adjust for inflation, however, you get a different story. The inflation-adjusted price has stayed relatively flat over time with minor fluctuations. The purchasing power of our currency in circulation has gone down over time, driving up the price of goods.

    As Mark Perry points out, this is no reason for despair. The average hourly wage of the American worker has increased steadily, making Thanksgiving more affordable than ever. That is something to be thankful for this year.

    The data for this chart was collected by the American Farm Bureau Federation. I adjusted this price data for inflation using the BLS’s CPI Inflation Calculator. The chart was built using Chart.js.

    I retooled my original 2014 version. I paid closer attention to colors and made this one responsive. I think it is a big improvement!

    This was also published over at FEE’s Anything Peaceful blog.

  • Sol LeWitt’s Wall Drawings 852 and 853 with D3.js


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

    I had an insight while going through the D3.js documentation to find a solution to another piece: d3.area() with a highly curved fit line isn’t that different from wall drawings 852 and 853! By the way, 852 and 853 are actually distinct pieces, though they are often grouped together into one display like the one at MASSMoCA. I worked on the solution to 852 first, then modified it to make 853:

    Wall Drawing 852: A wall divided from the upper left to the lower right by a curvy line; left: glossy yellow; right: glossy purple.

    Wall Drawing 853: A wall bordered and divided vertically into two parts by a flat black band. Left part: a square is divided vertically by a curvy line. Left: glossy red; right: glossy green; Right part: a square is divided horizontally by a curvy line. Top: glossy blue; bottom: glossy orange.

    Here are previews of 852 and 853 respectively:

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

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

    They are also available as blocks: 852 853

    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.

    Since d3.area() makes an area graph with given points, I had to create a data set of points. I wanted the start and end points to be defined with random (but constrained) points in the middle. Here is what I came up with for 852:

    var	ww = window.innerWidth, 	wh = window.innerHeight;  function getRandomArbitrary(min, max) {   return Math.random() * (max - min) + min; }  function lineData() { 	var data = new Array(); 		for (var point = 0; point < 5; point++) { 			var x = getRandomArbitrary(ww/10, ww-ww/10); // Constrains within the middle 80% 			var y = getRandomArbitrary(wh/10, wh-wh/10);		 				data.push({ 				x: x, 				y: y 			}) 		} 		// Starting point upper left 		data.push({ 			x: 0, 			y: 0 		}); 		// End point lower right 		data.push({ 			x: ww, 			y: wh 		}) 	 	return data; }

    For 853, things were a little trickier since the left is oriented vertically:

    var ww = window.innerWidth, 	wh = window.innerHeight - 80, 	halfwidth = ww/2 - 60;	  function getRandomArbitrary(min, max) {   return Math.random() * (max - min) + min; }  function fillLeft() { 	var data = new Array(); 		for (var point = 0; point < 3; point++) { 			var x = getRandomArbitrary(halfwidth/10, halfwidth-halfwidth/10); // Keeps within the middle 80% 			var y = getRandomArbitrary(wh/10, wh-wh/10);		 				data.push({ 				x: x, 				y: y 			}) 		} 		data.push({ 			x: halfwidth/2, 			y: 0 		}); 		data.push({ 			x: halfwidth/2, 			y: wh 		}) 	 	return data; }   function fillRight() { 	var data = new Array(); 		for (var point = 0; point < 3; point++) { 			var x = getRandomArbitrary(halfwidth/10, halfwidth-halfwidth/10); // Keeps within the middle 80% 			var y = getRandomArbitrary(wh/10, wh-wh/10);		 				data.push({ 				x: x, 				y: y 			}) 		} 		data.push({ 			x: 0, 			y: wh/2 		}); 		data.push({ 			x: halfwidth, 			y: wh/2 		}) 	 	return data; } 

    d3.area()

    One of the most important things to note about d3.area() is that you must sort your data sets (by x if the chart is horizonal, y if vertical) before passing them to the function. Otherwise you end up with something like this because the values are out of order:

    Out of order values!

    D3 has selection.sort() built in, but you also need to pass a function telling it how to sort:

    .sort(function(a,b) { return +a.x - +b.x; }) // Sorting by x ascending .sort(function(a,b) { return +a.y - +b.y; }) // Sorting by y ascending

    Most area charts tend to be horizontal, and nearly all examples you can find are structured in this way. You need to pass .x, .y0, and .y1:

    var area = d3.area()     .x(function(d) { return d.x; })     .y0(window.innerHeight)     .y1(function(d) { return d.y; })     .curve(d3.curveBasis);

    If you are switching to a vertical orientation, you instead need to pass .y, .x0, and .x1:

    var areaLeft = d3.area() 	.x0(0)     .x1(function(d) { return d.x; })     .y(function(d) { return d.y; })     .curve(d3.curveBasis);

    Curves and Points

    I played with a number of curve functions and a number of points to see how they compared to traditional interpretations of Sol LeWitt’s pieces:

    • curveCatmullRom
    • curveCardinal
    • curveBasis
    • curveNatural
    • curveLinear

    I eventually settled on curveBasis for both pieces. It creates the smoothest curving line with the given random points, which produces results similar to the curved lines in Sol’s earlier work. curveCatmullRom was my second choice, but occasionally produced harsh concave regions.

    For the larger standalone piece (852) I used 7 total points, including the end points. For 853, which consists of two different curves, I used 5 points each since the widths were smaller.

    Rebuilding on screen resize

    When you resize the screen, the divs gets destroyed and then rebuilt based on the new screen size. 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 node divs 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 sol852();  $(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("div.node").remove(); 	 sol852(); });

    Tools Used

    • D3.js – The D3.js library is well-suited to Sol LeWitt’s works. D3’s foundational principle of joining data to elements is easy to apply to LeWitt’s drawings.
    • 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:

  • Make Your Own Sol LeWitt 614!


    It is also available as a block.

    Background

    Here are Sol’s original instructions for Wall Drawing 614:

    Wall Drawing 614: Rectangles formed by 3-inch (8 cm) wide India ink bands, meeting at right angles.

    Technical Details

    For the technical details of making the drawing itself, check out my post on it. This post focuses on rebuilding the tool based on user input.

    The Inputs

    I used a form, a range input, an output, and some in-line JavaScript to power the sliders and display their values in real-time:

    Black band width: type="range" name="paddingInput" id="paddingInputId" value="15" min="1" max="50" oninput="paddingOutputId.value = paddingInputId.value"> name="paddingOutput" id="paddingOutputId">15px /> Number of rectangles: type="range" name="rectInput" id="rectInputId" value="40" min="5" max="300" oninput="rectOutputId.value = rectInputId.value"> name="rectOutput" id="rectOutputId">40

    Live example:

    Black band width: 15px
    Number of rectangles: 40

    Basing my functions on the values of the inputs

    A set a variable to the element I wanted to access, then I called the .value of that element in my functions. (See the post on 614 for more info about these functions.)

    var padding = document.getElementById("paddingInputId"); var rectNumber = document.getElementById("rectInputId");  function treeData() {   var obj = {name: "rect"};   var children = [];   for (var row = 0; row < rectNumber.value; row++) {     children.push({id: row, value: getRandomArbitrary(60, 1000)})   }   obj['children'] = children;   return obj; }  var treemap = d3.treemap()     .size([width, height])     .padding(padding.value)     .round(true)     .tile(d3.treemapBinary);

    Rebuilding after inputs are changed

    Similar to rebuilding on screen resize in the original version, I detect when there is a change in one of the inputs and then call a function to remove the divs and rebuild the treemap based on the inputs. jQuery makes this kind of thing fast and easy:

    $( "#paddingInputId" ).change(function() {   	d3.selectAll("div.node").remove(); 	sol614(); });  $( "#rectInputId" ).change(function() {   	d3.selectAll("div.node").remove(); 	sol614(); });

    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 works. D3’s foundational principle of joining data to elements is easy to apply to LeWitt’s drawings.
    • jQuery – I’m using jQuery to detect changes in the window size and trigger removing & rebuilding the visualization.
  • Sol LeWitt’s Wall Drawing 614 with D3.js Treemap and Randomization


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

    Wall Drawing 614: Rectangles formed by 3-inch (8 cm) wide India ink bands, meeting at right angles.

    Here is a preview:

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

    It is also available as a block.

    Design Details

    • LeWitt’s instructions are pretty open. The drafter can choose the number of rectangles. I chose 40.
    • Since screens work in pixels instead of inches, I chose to make the bands 15px wide. I tried various configurations and I think 15px
    • 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.
    • If you like this, I also made a version that you can customize.

    Technical Details

    • The placement and size of the rectangles are handled by d3.treemap().
    • I tried a few different tiling methods and decided to use d3.treemapBinary. I liked the look of it the best.
    • Each viewer gets a unique experience because the size of each rectangle 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 that creates the underlying data set on this piece. I owe major props to Eric Davis on helping me figure this out. I was getting close, but nothing I made was accepted by treemap(). He helped me identify my issues, which included making this data set and then passing it to d3.hierarchy before passing it to treemap.

    function getRandomArbitrary(min, max) { 	  return Math.random() * (max - min) + min; }  function treeData() {   var obj = {name: "rect"};   var children = [];   for (var row = 0; row < 40; row++) {     children.push({id: row, value: getRandomArbitrary(60, 1000)})   }   obj['children'] = children;   return obj; }

    Working with treemap

    One of the difficulties of D3.js transitioning from v3 to v4 recently is that most of the tutorials you can find on the web no longer work. Thankfully Mike Bostock created a great example of a treemap with v4 that I referenced quite a bit.

    After a few passes through the documentation and a call on my friend Eric Davis, we figured out how to pass data to d3.treemap():

    1. Create a data set that has a clear parent-child structure with unique parents
    2. Pass this to d3.hierarchy
    3. Call .sum() on d3.hierarchy and sum the values before passing it to treemap
    4. Pass it to treemap

    See below:

    var width = window.innerWidth + 30, 	height = window.innerHeight + 30; var format = d3.format(",d");  var treemap = d3.treemap()     .size([width, height])     .padding(15)     .round(true)     .tile(d3.treemapBinary);  var tree = d3.hierarchy(tree);  tree.sum(function(d) { return d.value; }); // always log for debugging! console.log(tree);  treemap(tree);  d3.select("body") 	.selectAll(".node") 	.data(tree.leaves()) 	.enter().append("div") 	  .attr("class", "node") 	  .attr("title", function(d) { return d.data.id; }) 	  .style("left", function(d) { return d.x0 + "px"; }) 	  .style("top", function(d) { return d.y0 + "px"; }) 	  .style("width", function(d) { return d.x1 - d.x0 + "px"; }) 	  .style("height", function(d) { return d.y1 - d.y0 + "px"; }) 	  .style("background", "#fff");

    Rebuilding on screen resize

    When you resize the screen, the divs gets destroyed and then rebuilt based on the new screen size. 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 node divs 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 sol614();  $(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("div.node").remove(); 	 sol614(); });

    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 works. D3’s foundational principle of joining data to elements is easy to apply to LeWitt’s drawings.
    • 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:

    Another shot of the version on display at MASSMoCA:

    Detail shot of the version on display at MASSMoCA:

    If you like this, I also made a version that you can customize. Check it out.

  • 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:

  • Category Filtering with Isotope in Jekyll


    This is the most recent addition to my Jekyll Tools repository on GitHub. Isotope is a popular jQuery filtering and sorting plugin. I combined it with Liquid to generate category filtering in Jekyll.

    You can see it in action at http://cagrimmett.com/category-isotope/.

    You can find the code for this in my Jekyll Tools repo on GitHub.

    This works by using YAML front matter to set categories and then outputting those categories as buttons and class names to work with the Isotope plugin.

    Generate the buttons from categories:

     class="button-group filter-button-group"> 	{% for category in site.categories %} 		 class="button" data-filter=".{{ category | first }}">{{ category | first }} 	{% endfor %} 		 class="button active" data-filter="*">All 

    Generate your posts:

      class="grid"> 	{% for post in site.posts %}       class="element-item {{ post.category }}">          class="post-meta">{{ post.date | date: "%b %-d, %Y" }}          

    class="post-link" href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}

    {{ post.excerpt }}

    {% endfor %}

“All” is selected by default. The other buttons come from the category you specify at the top of a post in your YAML front matter.

Include the jQuery and Isotope libraries, then set up the functions to trigger the filtering and setting an “active” class on your buttons so you can highlight the active one:

  
// init Isotope var $grid = $('.grid').isotope({   // options }); // filter items on button click $('.filter-button-group').on( 'click', 'a', function() {   var filterValue = $(this).attr('data-filter');   $grid.isotope({ filter: filterValue }); }); $('.button-group a.button').on('click', function(){ 	$('.button-group a.button').removeClass('active'); 	$(this).addClass('active'); }); 
  • Point Reyes National Seashore


    Amanda and I spent a few days in California wine country at the end of March before we drove over to Yosemite. We were kind of disappointed in wine country because we expected to learn a lot more than any of the tour guides seemed to be interested in teaching us, so we took one of the days and drove over to the Point Reyes National Seashore.

    That was a much better choice than visiting more wineries. The weather was wonderful and the scenery was incredible. We spend the morning horseback riding through parts of Point Reyes with the Five Brooks Ranch, then hopped in the car and drove out to the lighthouse point.

    Point Reyes Lighthouse

    Cliffs at Point Reyes

    Cliffs at Point Reyes

    Waves at Point Reyes

    Amanda in the Wind at Point Reyes

    Waves at Point Reyes

    Point Reyes Lighthouse

    Waves at Point Reyes

    Point Reyes Sand Dunes

    Point Reyes Pier

    Point Reyes golden hour

    Point Reyes golden hour

    Fishing boat, Point Reyes

    We got to see elephant seals for the first time, which was pretty awesome. They were so much louder than I was expecting. We could hear them from 1/4 mile away. It was windy and the temperature was dropping around golden hour, but we didn’t care. We stood and watched the seals for at least 30 minutes.

    Point Reyes golden hour

    Point Reyes has a number of leased ranches and pastures inside its borders. What a great place to be a cow!

    Cows grazing inside Point Reyes during the sunset

    Cows grazing inside Point Reyes during the sunset

  • Jekyll 3.2 Undefined Method Downcase Error


    I upgraded to Jekyll 3.2.1 recently and got a strange error message when I ran jekyll build:

    jekyll 3.2.1 | Error:  undefined method 'downcase' for #

    After some searching, I came across an open issue related to this on Github.

    The issue seems to be caused by a change in 3.2 that now reserves the config key theme to specify a gem-based theme for Jekyll. This means that you can’t use the key theme in your config.yml file to specify config settings for your jekyll theme. This was a standard practice for a lot of older Jekyll themes, so I expect this to be a somewhat common problem.

    For example, in my config.yml file, I had the following:

    # THEME-SPECIFIC CONFIGURATION theme:   # Meta   title: Chuck Grimmett   avatar: avatar.png   gravatar: # Email MD5 hash   description: "Chuck Grimmett's blog" # used by search engines

    The fix is to change the theme key to something else. I chose template. You not only have to change this in your config.yml file, but you also have to change anywhere that accesses it in your template files. The string you are looking for here is site.theme.* and is usually in your includes and layout files (look for folders called _includes and _layouts).

    I changed that section of my config.yml to this:

    # THEME-SPECIFIC CONFIGURATION template:   # Meta   title: Chuck Grimmett   avatar: avatar.png   gravatar: # Email MD5 hash   description: "Chuck Grimmett's blog" # used by search engines

    Then I did a global search for site.theme. and replaced it with site.template.

  • Comparing Sheet of Data in Excel


    Here is a problem I was faced with at work last week: Individuals who had two different kinds of relationships with an organization had two different contact records stored in two different files in a legacy database. The client wants to collapse those contact records down into one if possible, so we had to do a comparison between then.

    Difficulties:

    1. Names were concatenated in one file and stored separately in the other.
    2. Some addresses didn’t match (which is what we were checking in the first place), but even if they did, they were often entered differently between the two files (APT vs #, ST vs St., S vs South).
    3. In one file, all postal codes were stored in one column. In the other file, domestic postal codes were stored in one column and international postal codes were stored in another column.
    4. One file had about 30 duplicates for some reason. This means there were multiple entries in the database, but for some reason they all contained exactly the same information.

    First things first: I got the information in a CSV file for comparison. I pulled this into Excel. Thankfully there was a unique ID between the two files that matched, so I was able to quickly deduplicate the first file and get the number of entries to match. Then I sorted the two files in the same order.

    Here are the formulas I used for comparisons:

    Compare cells on two different sheets and put out Yes if they match, No if they do not: =IF(E2='Sheet 2'!C2,"YES","NO")

    Compare the first 5 characters of two cells instead of the whole contents. This is how I solved the whether or not addresses “matched” even if they have slight issues (APT vs #, ST vs St., S vs South). This won’t work for every situation, but I spot checked the cells and didn’t find any issues in my data set. =IF(LEFT(E2,5)=LEFT(F2,5),"YES","NO")

    Counting the number of NOs in a particular column: =COUNTIF(G2:G150,"NO")

    Count the number of YESes or NOs in a particular row. This will give you a good indicator of whether or not a row matches overall: =COUNTIF(H2:AC2,"NO") =COUNTIF(H2:AD2,"YES")

  • Smooth Pie Chart Transitions with D3.js


    Hey, so this post is broken. I moved platforms and some of my old tutorials don’t play nicely with WordPress. I’m working on fixing them, but in the meantime you can view the old version here: https://cagrimmett-jekyll.s3.amazonaws.com/til/2016/08/27/d3-transitions.html

    A few days ago we made a pie chart that updates in real time, but it has one issue: The update is jumpy. Let’s fix that.

    I’ll admit, unlike the other tutorials where I was able to figure out most of this on my own, I had to mine other examples to figure this out. I primarily followed Mike Bostock’s Pie Chart Update, II, but his commented Arc Tween example was extremely helpful in understanding what d3.interpolate is doing.

    What to do

    Note: We’re starting with code from my previous Pie Chart Update tutorial.

    First we need to store the beginning angle for each arc. You’ll recall that I’m using two separate arcs, one for the main chart and one for the labels. For about 10 minutes I was trying to figure out why the first update was jumpy but all subsequent ones were smooth. It turns out that we need to store the initial angles for each set of arcs:

    g.append("path") 	.attr("d", arc) 	.style("fill", function(d) { return color(d.data.letter);}) 	.each(function(d) { this._current = d; }); // store the initial angles;  g.append("text") 	.attr("transform", function(d) { return "translate(" + labelArc.centroid(d) + ")"; }) 	.text(function(d) { return d.data.letter;}) 	.style("fill", "#fff") 	.each(function(d) { this._current = d; }); // store the initial angles;

    Next we need to write two arcTween functions to transition between the two. I followed Mike Bostock’s example for the first one, then adapted it to the label arc, too:

    function arcTween(a) {   var i = d3.interpolate(this._current, a);   this._current = i(0);   return function(t) {     return arc(i(t));   }; }  function labelarcTween(a) {   var i = d3.interpolate(this._current, a);   this._current = i(0);   return function(t) {     return "translate(" + labelArc.centroid(i(t)) + ")";   }; }

    Last we need to include these arcTween() functions into the change() function we wrote before. I commented out the previous updates so you can compare them. The duration is 1/2 a second:

    function change() { 	var pie = d3.pie() 		.value(function(d) { return d.presses; })(data); 	path = d3.select("#pie").selectAll("path").data(pie); 	//path.attr("d", arc); 	path.transition().duration(500).attrTween("d", arcTween); // Smooth transition with arcTween 	//d3.selectAll("text").data(pie).attr("transform", function(d) { return "translate(" + labelArc.centroid(d) + ")"; }); 	d3.selectAll("text").data(pie).transition().duration(500).attrTween("transform", labelarcTween); // Smooth transition with labelarcTween }

    Here is is in action. As always, you can view source to see the fully integrated example: