Search This Blog

Knowing the Basics

We need to know an awful lot of stuff to be effective programmers. That isn't so incredible a claim, really. To be effective in any profession, you need to know a lot of stuff. But I don't know many other professions. I know how to be a programmer and what it entails, so that's what I'll focus on here. As programmers we need to know syntax, control flow, libraries, data structures, algorithms, design patterns, programming environments, paradigms, protocols, and good practices. That may be a long list, but it only scratches the surface.
If we need to know so much to be effective, how can it be done? What are the most important things to learn to get started programming and to continue climbing the learning curve from wherever we happen to be? We want to figure out what topics are going to give us the most bang for our buck, and learn those things well. The rest of the knowledge we need to get the job done can be paged in as needed.

Taking a Cue from Computer Architecture

One thing that has stuck with me since college came from the introduction to computer architecture course. Near the beginning of the course we explored the various types of historical computer architectures. They were generally classified into two groups—CISC and RISC architectures. CISC (Complex Instruction Set Computer) architectures tried to provide solutions to the programming interface with instructions that had lots of different options and did large amounts of work per instruction. RISC (Reduced Instruction Set Computer) architectures provided a set of primitive instructions that could more easily be linked together and used in different ways to achieve the same goal with possibly more, but simpler, instructions.

Compiler writers found the RISC architectures much easier to work with because the simpler instructions could be combined in many more ways and used under a much wider variety of contexts than the more rigid CISC instructions. Computer architects also found the RISC architectures to be easier to design to, and they were able to more effectively implement microarchitectural features like branch prediction, pipelining, and out-of-order execution. RISC architectures ended up being better on both sides of the hardware-software interface, and over time the CISC processors died out and RISC processors took over. Even Intel's dominant x86 architecture, which started out as a CISC architecture, became more RISC-like over time, both in the types of instructions exposed in assembly language and how the instructions were translated into microcode for the pipeline to execute.
RISC primitives were found to be much more useful for a wider variety of problems than pre-packaged CISC solutions, and they often led to higher-performance code.

Primitives and Solutions in Programming Languages

How does choosing primitives over solutions translate to software engineering? To answer that question, let's compare two languages—Java and C. I used to know Java. I used it for a number of classes in college. (I know that doesn't mean I really knew Java. I only used it incidentally and superfluously for some class projects.) I didn't experience the OO cathedral that Neil Sainsbury talked about in this post on why it's painful to work in Java for Android development, but I did get an early taste of it. If what he says is true, then the Java libraries have been built up into extensive frameworks that are trying to be solutions, and as was already noted, solutions have problems.

When solutions grow in an attempt to address more and more of a problem space, they necessarily become more generic. They become less applicable to any particular problem because they have to increase their surface area to cover all of the issues related to other problems that are within the same domain. All of this extra configuration and layers of architecture make the frameworks more complicated and more difficult to use. As the libraries keep expanding in both number and size, no programmer is able to keep all of the details in their head and one's ability to understand the big picture of how to use a language and its libraries starts to plummet. At some point it's worth questioning if a framework is really adding value, or if you are spending as much time understanding the framework as you would spend building up a more targeted solution from simpler primitives.

In contrast, C libraries exhibit the approach of supplying primitives for the programmer to use as building blocks. Heavy frameworks are much more rare in the C community, so primitives are used more often to solve problems. Of course, primitives have a number of problems of their own. It may take longer to implement a solution from primitives if a framework exists that is a good fit for the problem at hand. If you blindly use primitives without checking out what's available, you could be reinventing the wheel while recreating mistakes that have already been made and fixed in an available library, especially security or memory safety mistakes in the case of C.

Clearly, primitives shouldn't always be used when a better solution is available, but they do have a number of benefits that should be considered. In C you can hold nearly everything about the language and its standard library in your head. Once you learn the language and libraries, you're done. It's possible to pull those primitives from your working memory and use them efficiently without having to dig through mountains of documentation or relying on your IDE to constantly provide hints. You know how things work, and you have total control over what's happening in your application. This level of control allows you to cut out unnecessary cruft and maintain a highly optimized code base.

Keep in mind that using primitives doesn't guarantee a clean, optimized code base. Nor does using large frameworks prevent it. In either case clean code requires diligence and skill to achieve, but if a framework doesn't fit the problem—if the framework is too large or poorly targeted—then using primitives is more likely to lead to a better solution. Also note that I'm not picking on Java or C here. Both languages have their strong points and their drawbacks, and both work well for certain types of problems. They happen to exhibit certain tendencies in their libraries and frameworks that could as easily be shown by comparing C# and the .NET framework with Haskell or Ruby and its Gems with LISP. Remember, the best language doesn't exist.

The point is that building up solutions from first principles can be better than trying to memorize a lot of heavy frameworks. Thoroughly learning the basics gives you a set of robust tools that you can use in a wide variety of situations. Knowing a certain amount of the basics is essential to being a good programmer, and the more you learn, the better you get. Learning a large framework is less beneficial because preferred frameworks change frequently, they're hard to memorize and understand completely, and worst of all, they don't teach you much about how to solve problems. They just give you the answers.

Building a Foundation

Okay, if it's much more worthwhile to learn primitives, how do we learn them? In this post on what you need to know to function as a software engineer, (read it if you have time; it's long, but entertaining) Steve Yegge talks about the astonishingly large number of rules you need to memorize, and accumulating that knowledge takes a long time. As a result more experience yields better developers, in general. But memorizing everything is hard. Gaining enough experience to be effective purely through memorization would take more than a lifetime to accomplish. There must be a way to speed up this process. After all, we certainly know of great programmers that are only on their first lifetime.

We need ways of linking these bits of programming knowledge together so that we can remember a much smaller set of basic things and derive the rest. The best way that I've found to ingrain this knowledge in my brain is to study and practice the basics enough to have a deeper understanding of why they are true and how they work together to solve problems. Separate fundamental ideas can fit together to form a coherent overall view of programming that makes it all easier to keep in your head.

As an example, let's turn to mathematics, specifically the quadratic formula. It is certainly possible to memorize the quadratic formula, and a lot of people do. A lot of people also forget it, especially if they don't ever have to use it in their day job. I'm not arguing that everyone needs to know the quadratic equation, but it is actually fairly straightforward to derive it from a more basic principle, namely from completing the sum of squares.

If you work out a few example second-order polynomial problems by completing the sum of squares and solving for x, you'll begin to notice a pattern in how the coefficients are manipulated to get to the answer. Once you see the pattern, it shouldn't be too hard to derive the quadratic formula on your own. When you understand completing the sum of squares well enough that you can derive the quadratic formula, you no longer have to worry about memorizing it. Next time you can figure it out again. Ironically, because you have that deeper understanding, you're also more likely to just remember it the next time you need it. The concept of the quadratic formula is resting on a solid foundation. It's a win-win.

Mathematics is filled with examples of deriving higher-order results from first principles. The entire field is built on that idea. In the same way, most of the ideas in programming can be built up from simpler primitives. If you deeply understand the fundamentals of object-oriented programming, you can easily derive design patterns and understand when and where to use them instead of over-applying them. If you deeply understand pointers and program memory, you can derive most simple data structures, and then simple data structures lead to the more advanced data structures. If you deeply understand control structures and recursion, you can derive many different algorithms and better understand how they work. Understanding how these ideas are built on primitives makes them easier to remember and use effectively.

The importance of fundamentals is probably why learning how to write a compiler is so instructive for programmers. Compilers use so many data structures, algorithms, and patterns that they're a one-stop shop for getting a deeper understanding of programming. While you're implementing a compiler, you're simultaneously learning how to use programming concepts effectively, exploring the underlying mechanics of a language at a deeper level, and discovering how the language interfaces with the lower-level machine, be it a virtual machine or a physical processor. You can't get more fundamental than that.

The Basics Lead to Better Programmers

Programmers often complain that learning basic data structures and algorithms is pointless, that those things are never used in day-to-day programming, but you never know when some low-level principle that you learned will come in handy. That may sound flippant, but it happens all the time. The more fundamental principles you know, the easier it is to brainstorm ideas that are likely to work. You can pull from a larger store of flexible primitives that can be pieced together to form a solution tailored to the problem at hand, and you may not even realize that you're doing it.

Learning the basics trains your mind in abstract problem solving in a way that memorizing solutions won't. Sure, you don't need to know the fundamentals to get work done. Plenty of programmers put together working software from heavy frameworks and libraries that solve all of their problems for them. But those programmers probably don't understand the tradeoffs they're making or how the system they built really works.

A programmer that does know how their code works and why things were done the way they were done is better equipped to handle the most difficult problems or the most complex features without making a total mess of the code base. Frameworks are certainly useful for solving a wide variety of design problems, but knowing the basics gives a programmer the wisdom to know when to use them and the confidence to roll a custom solution when necessary. To become a better programmer, start with knowing the basics.

The Best Programming Language Does Not Exist

In an argument about the best programming language, there are no winners. I'm not even sure there are any losers. When I see these types of debates on programming forums and news sites, my eyes glaze over and my mind begins to wander. Why do people fight so vehemently for a particular language and throw unqualified claims around that can't possibly be proven? I find that with every programming language I'm exposed to, I learn new things about what programming can be, and how to solve problems in new and interesting ways. No language is perfect. The best programming language does not exist, but there are quite a few good ones.

The problem with arguments about the best programming language is that any claim you could possibly make in favor of one language is fraught with innumerable exceptions that water down the whole argument and make it irrelevant. Context effectively kills any best programming language argument. As a result, the arguments for or against a language tend to be vague and allude to nebulous ideas of features, productivity, expressiveness, speed, safety, or simplicity. Once the debaters try to get into specifics, it's easy to find exceptions and counterpoints that poke holes in every argument.

When programmers bring up language features in an argument, it's generally safer to stick to the argument that a language is better because it has more features or better features. As soon as you try to point to specific features, those features expose the reality of trade-offs. Is it better for a language to have garbage collection or direct control of memory? Is dynamic or static typing better? Should the language be primarily procedural, functional or object-oriented? What about concurrency support, first-class functions, metaprogramming, generics, blocks, or closures? Every additional feature adds complexity to the language and cognitive load to the programmers that use it. I like the quote in this poster of programming paradigms, "More is not better (or worse) than less, just different."

It's commonly taken for granted that high-level languages are better for programmer productivity, and we continue to pursue higher levels of abstraction. But sometimes programming in lower-level languages can be more productive. Even seemingly safe arguments like, "No one still codes in assembly," aren't always true. Assembly may seem like a dead language that is only useful as a good learning experience, but there are still real-world cases where it is necessary. I've coded in assembly recently, at least the TI DSP form of it, because when doing DSP embedded programming, sometimes I needed total control over the algorithm and the hardware it was running on to fully optimize it. Being able to drop down to assembly for tight algorithmic loops has a tremendous impact on performance for data processing.

Taking the slightly different tack of arguing that some programming language is more expressive or powerful than another language runs into the same issues. I've seen claims of every language in common use (and then some) being tremendously expressive. It doesn't matter if it's C, Ruby, Haskell, or LISP. Every language is really, really expressive. And everyone is right. Each language is expressive and powerful in the domains that it's good for. The bottom line is that it depends on the context.

Another favorite argument is the speed of a language, and it's also meaningless when taken out of context. If the program isn't fast enough it's most likely either because of a design issue with the architecture of the program, or it's a bottleneck in a tight section of code. If the problem is the former, it's not the language's fault, and if it's the latter, just write that loop in C and call it from your preferred language. For most of any code base, it doesn't matter what language it's written in when it comes to speed.

Of course, the argument that language speed doesn't matter doesn't hold up in all cases, either. If you're writing for an embedded system or HPC (high-performance computing), you may not be able to use an interpreted language and ever get enough performance. That's fair, but those programmers aren't debating about whether to write in Ruby or Python, they're debating whether to write in C, C++, or maybe Lua. I fear I'm getting into the kind of arguments that end up proving my point. There are a bunch of weaknesses to the speed argument, and it's very context dependent. Any smart programmer can easily poke a bunch of holes in it, and they'd be right for the cases they're thinking about.

Programmers also make a whole host of arguments that are generalizations of specific problems they've struggled with. Most of these arguments boil down to a language being safer than others, and if they had just used that language, they could have avoided a world of hurt. They end up trying to prove a general rule with anecdotes. While the pain of the experience that lead to thinking a particular language was unsafe was surely real, generalizing that pain to apply to more circumstances than it warrants doesn't prove that a given language is broken. Even bringing up examples of some project failing or a company going out of business because of a language choice doesn't prove that the language is not production-worthy. Any reasonably popular language also has numerous examples of successful code running in the wild. Bugs happen and good programming practices help in any language.

A particular example of an impossible-to-win argument is that it is impossible to write safe C code. There will be a group of programmers that will agree with this statement and then a group of programmers that will vehemently disagree. The latter group will point to one or more instances of safe C code and the debate will devolve from there. The whole argument ends up being pointless because of a variety of reasons. To name but a few of them:
  • For plenty of programmers, C is one of a few options because they are working with legacy, performance-critical, or embedded systems. 
  • The people making decisions about which language to use sometimes aren't aware of the arguments against certain languages or are basing decisions on other factors. 
  • Programmers need to gain enough experience to write safe code in any language so language choice is only one, possibly minor, factor in writing safe code.
Part of the issue with arguing about programming languages is that there are very few useful statements about a language that are provably correct. (I was going to say negative statements, but after thinking about it, it holds true for positive statements as well.) The world of programming is so vast that someone is going to come up with a counterexample to almost any argument you can make for or against a programming language. For example, if I was to say that C# may be a great language, but it can only run well on Windows, a bunch of C# programmers would be beating down my door to tell me how the CLR and C# can most certainly run on Linux or iOS and here are the tools to make it happen. They're probably right for some definition of "run well."

In the end a lot of these arguments seem to be implicitly claiming that if we could only get everyone to program in language X, then all of our problems would be solved. That mentality is both wishful thinking and missing the real issues. Programmers can and will write bad code in any programming language. At the same time, great software that adds tremendous value can also be written in (almost) any programming language.

Programming language venn diagram

With such a tremendous amount of overlap, why waste time debating what the best programming language is? With every new language, I learn new ways of solving hard problems and the debate about which language is better becomes less interesting. Discussing what the great features of programming languages are or how to make languages better or how to write better code in a given language are much more interesting points of discussion. The best programming language may not exist, but there are plenty of good ones out there for writing great software.

Better Mileage Data with the 2013 Nissan Leaf

I've now had a 2013 Nissan Leaf for nearly 8 months, and temperatures here in Madison, WI have gone below zero, so I have a nice amount of data to share on this newer model. The 2013 Leaf S replaced the 2012 Leaf SL I had previously, and it includes a state-of-charge (SOC) percentage display on the dash that was lacking in the older models. This SOC reading is a major improvement to the unreliable GOM (Guess-O-Meter, or miles-to-fully-discharged meter) that I used before in my data collection.

I haven't invested in any other kind of meter for measuring the Leaf's battery state because I wanted to treat the car more like a normal driver would. Measuring internal battery messages off of the car's CANbus was decidedly outside of normal driver behavior. I did purchase a P4460 Kill-A-Watt power meter for measuring the amount of electricity that is consumed by charging the car. The on-board energy efficiency meter doesn't take charging losses into account, and I wanted to know exactly how much electricity the car is using. I'll report on those numbers as well.

Before getting into the numbers, I will say that I still greatly enjoy driving the Leaf. The 80kW electric motor is nice and torque-y, with zippy performance for around town and pleasing acceleration when jumping on the freeway. The power is especially evident when scaling steep hills, as the Leaf tears up inclines as if they aren't even there. And the ride is always smooth and super quiet.

The handling so far this winter has been pretty good as well. The traction and stability control and the ABS all work when they need to, and the car's low center of gravity from the under-carriage mounted battery helps quite a bit, too. The one thing that could be improved in snow is the stock tires. They don't have the best traction, and the other safety systems have to compensate when the tires slip. I'll probably finish out the winter with them since the tread is still pretty new, but next winter I'm going to switch to snow tires. We're using winter tires on the Prius this year, and they've had an insignificant effect on mileage, so I expect the benefits of using them on the Leaf to greatly outweigh the minor range hit that I'll take.

Data Collection Methodology

Collecting data on the Leaf was fairly straightforward. After every charging cycle, I would log the date, the charge percentage, and the accumulated kWh on the Kill-A-Watt meter. I nearly always charge to 80% unless I know I'm going on a long drive the next day. I was under the impression that the lower charge level was better for the battery. Although, I now hear that new Leafs will no longer have the 80% setting option. I'm not sure if that's because Nissan is trying to avoid consumer confusion, or because there really is no negative impact to the battery when charging to 100%. It seems reasonable that the latter could be true as long as the battery isn't charged until it gets below 80% SOC. The use case for a car battery is much different than for a laptop battery, where keeping it plugged in wears out the battery because it continually charges to 100% during use.

After each drive I keep a record of the %SOC, the odometer reading, and the outside temperature as reported on the dash. I won't charge every night if I don't need to, and I often bring the battery down to 10-20% before charging. I don't normally go below that since there isn't much useful range left for me to get to work and back again at that point. I have a new job with a shorter 16-mile round-trip commute through town instead of my old 23-mile round-trip commute on the beltline, so I can now go three or four days between charges in the summer. There's probably a trade-off between less depth-of-charge and less charging cycles for better battery life, but I have no idea where the optimal point is so I go for less charging cycles.

Once I have a good amount of data logged, I transfer it to Google Sheets to calculate range, average temperature, and miles/kWh. Estimating range is much easier with the %SOC numbers because all I have to do is subtract start and end odometer readings and divide by the %SOC used for those miles. I'm assuming that the miles/%SOC is linear for this calculation, but I'm not likely to push the limit to squeeze a few extra miles out of the battery at the end of the range, so assuming the same miles/%SOC over the entire range is acceptable to me. I'm still getting a reasonable estimate of range over many charging cycles.

I calculate an average temperature for each charging cycle by taking the average of temperatures for each driving segment weighted by miles driven in each segment. Temperature has a big effect on range, so getting an accurate value amidst big Midwest temperature swings is important. I'm sure that the temperature during charging also has an effect, but I don't know how I would estimate this effect without monitoring temperature during every charging cycle. I'm not set up to do that so I ignore that effect. Besides, charging temperature is heavily correlated with driving temperature, even though the Leaf is always charging in a garage. The garage is unheated so it's always a milder form of the outside environment.

The miles/kWh are calculated two ways. The car's measure of efficiency is recorded from the dash, and I let the meter run a measurement for a month before recording the value and resetting the meter. I also calculate the wall-to-wheels efficiency by dividing the miles travelled in a month by the kWh usage for that month from the Kill-A-Watt meter. I can then divide the wall-to-wheels value by the battery-to-wheels value to get an estimate of charging efficiency.

That's how I collect and massage the data, so let's take a look at what we've got.

What is the Real Range of a Leaf?

That is the most common question I get when I talk with people about the Leaf, and for good reason. Everyone knows EV ranges are limited right now, and the answer is it depends, of course. One thing it depends greatly on is temperature. Here's how much my Leaf's range changed with temperature in the last 8 months:

It's an interactive chart so you can zoom and get info on specific points with the mouse. Clearly, temperature is the dominant effect, and the range is cut in half over the temperature range. While I was getting about 100 miles of range at 75°F, I am getting only about 50 miles at 0°F. Luckily, I don't have to drive far to work. This plot does include a mix of stop-and-go city driving and free-way driving at around 55 mph. I did take the Leaf on the interstate once at 65 mph, but only for a short while and it doesn't noticeably show in the chart.

Two features to note in this chart are the outlier at 86°F and the wider variation in driving range at both ends of the temperature range, especially below 40°F. Regarding the outlier, this point happened to be a trip I took with the rest of the family to a high school graduation party. It was hot and raining so there was extra road resistance and I ran the A/C to keep everyone comfortable. The combination of extra weight, road resistance, and constant A/C resulted in about a 20% drop in range, which doesn't surprise me.

The wider variation at the high temperature range is likely due to there being more data points over a wider range of driving conditions. Then as the temperature dropped in the fall, the points followed a more linear curve into the colder temperatures of winter.

The main reason for the wide variation at cold temperatures is probably due to a number of reasons. Depending on temperature and humidity, I have to use the defroster more or less and sometimes I use the heated seats (although the seats don't seem to impact range much). If there's snow on the roads, that adds resistance and lowers efficiency. Lower temperatures happen to coincide with less daylight and inclement weather, so I use the headlights more and usage varies a bit more depending on the weather. Since I have normal headlights instead of the LED headlights that come as an option, they use more battery power. Finally, traffic varies more in the winter, and if I'm stuck in traffic, that amplifies all of the other losses, resulting in even more variation at cold temperatures.

Despite all of these variations, I was amazed at how much more linear this data is than the data from my 2012 Leaf, using the GOM to estimate range instead of the %SOC on the 2013 Leaf. Here is the scatter plot of the 2012 Leaf data for comparison:

Scatter plot of 2012 Leaf estimated range vs. temperature

This plot has many more data points, but it still looks like it has much more variation than the 2013 Leaf data does. It will also be interesting to see if the 2013 Leaf maintains its approximately 100 mile range next summer, since that seems to be better than the 2012 Leaf was while the lower temperature ranges are roughly equivalent. The regular headlights of the 2013 Leaf could be part of the reason for it not being more efficient than the 2012 Leaf in the winter.

Overall, I'm quite happy with the data I'm getting from the 2013 Leaf. I'm a bit less enthusiastic about the steep drop in range over temperature, but when I compare it to our Prius, the change in efficiency is not all that different. We normally get 55+ mpg from the Prius in the summer, but on one of those bitter cold winter days I only got 28 mpg. The big difference with the Prius is that its normal range is about 500 miles on a full tank. Cutting that range in half still leaves plenty of range to get where you need to go. When EVs have 300+ mile ranges on a charge, it won't be as big of a deal when the range drops in the winter.

How Much Does it Cost to Charge?

This is the second most common question I get about the Leaf. So far I've driven 3,811 miles and measured 983 kWh of electricity use from the wall. With an electricity usage rate of $0.18/kWh, it's cost me $177 to drive that 3,811 miles. If I compare that to a car that gets 30 mpg, it would be like paying $1.39 for a gallon of gas. The price of gas has dropped quite a bit, but it hasn't dropped quite that far. Also, paying for electricity has the advantage of being a relatively fixed rate. It doesn't change nearly as much as the price of gas, and gas prices have been much higher in the past and probably will be higher in the future.

Beyond the absolute cost of charging the Leaf, it's interesting to look at the charging efficiency. I always charge with the 110V trickle charger (except once) since I have plenty of time at night, and I've never had a problem finishing a charge before driving the next day. Using a Kill-A-Watt power meter at the wall outlet and the on-board energy efficiency meter in the Leaf, I can measure the wall-to-wheels and battery-to-wheels efficiency, respectively. After doing this for 8 months and grouping the data by month, I get the following results (September and October are combined because of a long vacation where the Leaf sat idle):

Leaf Energy Efficiency bar graph

The charging efficiency is easily calculated by dividing the wall-to-wheels efficiency by the battery-to-wheels efficiency, and it hovers around 80%, dropping slightly to 75% in November. I'm not quite sure why that happened. Another behavior that this chart shows is that the drop in energy efficiency does not fully explain the drop in range at lower temperatures. If that were the case, then the Leaf should have a range of about 80 miles in the winter, but I was averaging more like 60 miles for the last couple months. This discrepancy must mean that both the energy efficiency and the battery capacity drops with temperature. While the usable battery capacity is 19-20 kWh in the summer, it dropped to 15 kWh or less in the cold, accounting for about half of the range loss.

Because of the range loss in the cold, the Leaf is definitely not the best car choice for everyone. If you live in a cold climate, you have to be careful to make sure you have enough range to get where you need to go or have a backup plan when the temperature drops too far. My commute is plenty short, so it works quite well for me. I love driving around in a smooth, fast, quiet car. I look forward to driving it everyday, and I couldn't imagine going back to an ICE car willingly. Once battery capacity catches up with our needs, we'll be looking to get out of our Prius and into a longer-range EV. In the mean time, I'll be enjoying the Leaf and will continue to collect data to see how it performs over time. It will be interesting to see what next summer brings.

A Barely Adequate Guide to JavaScript Charts

I show a fair number of charts on this blog, especially when I'm talking about my Nissan Leaf data, and I've been getting tired of showing boring pictures of charts generated from Google Sheets. Sure, they look nice and it's easy to do, but I wanted something a little more interactive. I thought I could put in a little more effort and spruce up my data presentation a bit, so in the vein of my last Barely Adequate Guide, I'm going to write this post while figuring out how to use a JavaScript charting framework. The idea is to come up to speed as fast as I can on at least one charting framework, and get a functional example working in this post. No detailed analysis. No in-depth guide to every feature. Just do the simplest thing that could possibly work. This shouldn't be too hard, so let's get started.

Figuring Out a Chart Framework

First as always, it's time for a Google search. After looking up "javascript charts," on the first results page I get an even distribution of chart frameworks and sites that list chart framework options:
  1. Highcharts
  2. Chart.js
  3. The 15 Best JavaScript Charting Libraries
  4. amCharts
  5. Comparison of JavaScript charting frameworks
  6. JavaScript Charting Library - Stack Overflow
  7. Emprise JavaScript Charts
  8. 50 JavaScript Libraries for Charts and Graphs
  9. CanvasJS
  10. D3.js
Taking the first one from the list, Highcharts looks beautiful, and right on the demo pages is a link to JSFiddle where I can play with the chart options and fiddle (heh) with the code so it's exactly how I want it before including it in the article. Here's my first attempt with the demo chart from Highcharts for a chart I use a lot, the scatter plot:

This is pretty slick. You can highlight data points with the cursor, zoom in by dragging a box around points, and zoom out by clicking the 'Reset zoom' button. To get the chart to draw correctly, I had to do a few things. First, I included the required jQuery JavaScript library in my Blogger HTML template at the bottom of the header with the following line of HTML:
<script src="//
Then I added a couple more lines to the HTML of this post so that the Highcharts JavaScript will load and a <div> is defined for holding the chart where it should be drawn:
<script src="">
<script src="">
<div id="test_chart" style="height: 400px; margin: 0 auto; 
  max-width: 800px; min-width: 310px;"></div>
The two <script> tags only need to be included once per post that uses charts, and I don't include it in the Blogger template so that it doesn't needlessly load the Highcharts JavaScript for posts that don't use it. That means there will be a little redundancy when multiple posts that use charts are loaded on the same page, but I'm okay with that inefficiency.

The last step was to copy the chart code, including the data, into my post. I'll show a snippet of it here:
<script type="text/javascript">
$(function () {
    chart: {
      borderRadius: 8,
      type: 'scatter',
      zoomType: 'xy'
    // boatload of chart options and data
    // ...
The complete code can be found at JSFiddle, where it's trivially easy to play around with different settings and see how the chart changes. The fact that they have all of this demo code posted at JSFiddle is great. I couldn't believe how easy it was to get this working. The experience was totally seamless. They also have excellent documentation on all of the chart options in an easy to browse format.

Applying What I've Learned

Now that I have a working chart, the next task is to see how easy it is to convert some of my own data into the right format and include it in a chart. After all, I need to have charts with my own data in them, right? Since I have a bunch of Leaf battery data, I'll use that. I found that I first had to format the data so I could easily add it to the chart's JavaScript. In Google Sheets I separated each data set into its own sheet with a column for temperature and another column for estimated range. I ended up with four sheets for the data sets for 2012H2, 2013H1, 2013H2, and 2014H1.

I saved each sheet to my computer as CSV files, and then using a little Vim-fu, I added the necessary brackets to get the data into the [[temp1, miles1], [temp2, miles2], …, [tempN, milesN]] format needed for the chart's data series section. Then it was a simple copy and paste into JSFiddle to check that the chart worked, and another copy and paste of all of the JavaScript into the post. If I was going to do this a lot, I'd probably write a script to generate more of the JavaScript, but for this test the manual editing was fine. I end up with this:

Nice! The other neat thing about these charts is that you can click on the labels in the legend to toggle the data sets on and off—very useful when you have a lot of points, like in this chart. I'd say this chart is sufficient for the things I want to do, so this exercise has been a success. But what about other options? I haven't even looked at anything else.

Looking at Other Options

To quickly evaluate some other options, I took a look at the rest of the top 10 Google results. The 15 Best JavaScript Charting Libraries article has a decent overview of the main charting libraries, including Highcharts, but it doesn't go into too much detail about what differentiates the libraries. The Wikipedia comparison has a more complete list of charting libraries, and at least on the metrics chosen by the Wikipedia authors, there really isn't much differentiation among them. All of the libraries more or less provide similar features, so unless there's a critical features that only some of the libraries support, it probably boils down to a matter of taste. Here is what I found from my own brief look at a few of the other libraries.

Chart.js - This looks like a simple, straight-forward library that allows you to create clean, elegant charts without a lot of extra cruft. It looks like it's a bit too simple for the features that I wanted, but if I wanted a no-frills chart that looked great, I'd definitely consider Chart.js.

Google Charts - It looks like Google exposed the API for their chart creation feature in Google Sheets with this library. The documentation looks great, the charts are easily recognizable by anyone that uses Sheets, and they seem to be very fast. They also look to be quite fully featured with scatter plots and zoom capability.

D3.js - This library is like the assembly language of charts. It gives you incredibly precise control over every aspect of charting, and it allows you to make all kinds of different charts beyond the basic bar/line/pie charts that most libraries offer. The flexibility of this library is readily apparent in this gallery of D3.js charts, and it's truly astounding. Unfortunately, I don't have the time to get good at something this complex.

amCharts - Probably the most beautiful charts out of the box, amCharts is an extensive charting library that's as easy to use as Highcharts or Google Charts. There's also an online chart builder that looks pretty nice—kind of like a JSFiddle made specifically for their library. The library requires a license for commercial use and otherwise has an embedded link on every chart.

There are many more options, but they all start to look alike after a while. I would have to use them extensively to ferret out more of the trade-offs, and I'm sure each one has situations where it would be the best choice. As it is, I'm quite happy with Highcharts. It was super easy to get up and running for this blog, and the documentation is so good that I can quickly find what I need, even if I'm only using the library a couple times a month. Who knows? Because of how easy it is to use, I might end up using it more than that. We shall see.