15 December, 2015
by nitaku

Weather wheel

A recreation of this nice infographic in D3.js, with some modifications. A year of weather measurements is displayed in a single overview, highlighting seasonal processes. Data is obtained by querying Weather Underground's historical API.

A polar floating bar chart is used for minimum and maximum temperatures, while a HCL-interpolated color scale is used for means. Area encoding is instead used for precipitation (outer ring).

File not shown (binary encoding).
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  typeof define === 'function' && define.amd ? define('d3-path', ['exports'], factory) :
  factory((global.d3_path = {}));
}(this, function (exports) { 'use strict';

  var pi = Math.PI;
  var tau = 2 * pi;
  var epsilon = 1e-6;
  var tauEpsilon = tau - epsilon;
  function Path() {
    this._x0 = this._y0 = // start of current subpath
    this._x1 = this._y1 = null; // end of current subpath
    this._ = [];
  }

  function path() {
    return new Path;
  }

  Path.prototype = path.prototype = {
    moveTo: function(x, y) {
      this._.push("M", this._x0 = this._x1 = +x, ",", this._y0 = this._y1 = +y);
    },
    closePath: function() {
      if (this._x1 !== null) {
        this._x1 = this._x0, this._y1 = this._y0;
        this._.push("Z");
      }
    },
    lineTo: function(x, y) {
      this._.push("L", this._x1 = +x, ",", this._y1 = +y);
    },
    quadraticCurveTo: function(x1, y1, x, y) {
      this._.push("Q", +x1, ",", +y1, ",", this._x1 = +x, ",", this._y1 = +y);
    },
    bezierCurveTo: function(x1, y1, x2, y2, x, y) {
      this._.push("C", +x1, ",", +y1, ",", +x2, ",", +y2, ",", this._x1 = +x, ",", this._y1 = +y);
    },
    arcTo: function(x1, y1, x2, y2, r) {
      x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;
      var x0 = this._x1,
          y0 = this._y1,
          x21 = x2 - x1,
          y21 = y2 - y1,
          x01 = x0 - x1,
          y01 = y0 - y1,
          l01_2 = x01 * x01 + y01 * y01;

      // Is the radius negative? Error.
      if (r < 0) throw new Error("negative radius: " + r);

      // Is this path empty? Move to (x1,y1).
      if (this._x1 === null) {
        this._.push(
          "M", this._x1 = x1, ",", this._y1 = y1
        );
      }

      // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.
      else if (!(l01_2 > epsilon));

      // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?
      // Equivalently, is (x1,y1) coincident with (x2,y2)?
      // Or, is the radius zero? Line to (x1,y1).
      else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon) || !r) {
        this._.push(
          "L", this._x1 = x1, ",", this._y1 = y1
        );
      }

      // Otherwise, draw an arc!
      else {
        var x20 = x2 - x0,
            y20 = y2 - y0,
            l21_2 = x21 * x21 + y21 * y21,
            l20_2 = x20 * x20 + y20 * y20,
            l21 = Math.sqrt(l21_2),
            l01 = Math.sqrt(l01_2),
            l = r * Math.tan((pi - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),
            t01 = l / l01,
            t21 = l / l21;

        // If the start tangent is not coincident with (x0,y0), line to.
        if (Math.abs(t01 - 1) > epsilon) {
          this._.push(
            "L", x1 + t01 * x01, ",", y1 + t01 * y01
          );
        }

        this._.push(
          "A", r, ",", r, ",0,0,", +(y01 * x20 > x01 * y20), ",", this._x1 = x1 + t21 * x21, ",", this._y1 = y1 + t21 * y21
        );
      }
    },
    arc: function(x, y, r, a0, a1, ccw) {
      x = +x, y = +y, r = +r;
      var dx = r * Math.cos(a0),
          dy = r * Math.sin(a0),
          x0 = x + dx,
          y0 = y + dy,
          cw = 1 ^ ccw,
          da = ccw ? a0 - a1 : a1 - a0;

      // Is the radius negative? Error.
      if (r < 0) throw new Error("negative radius: " + r);

      // Is this path empty? Move to (x0,y0).
      if (this._x1 === null) {
        this._.push(
          "M", x0, ",", y0
        );
      }

      // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).
      else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) {
        this._.push(
          "L", x0, ",", y0
        );
      }

      // Is this arc empty? We’re done.
      if (!r) return;

      // Is this a complete circle? Draw two arcs to complete the circle.
      if (da > tauEpsilon) {
        this._.push(
          "A", r, ",", r, ",0,1,", cw, ",", x - dx, ",", y - dy,
          "A", r, ",", r, ",0,1,", cw, ",", this._x1 = x0, ",", this._y1 = y0
        );
      }

      // Otherwise, draw an arc!
      else {
        if (da < 0) da = da % tau + tau;
        this._.push(
          "A", r, ",", r, ",0,", +(da >= pi), ",", cw, ",", this._x1 = x + r * Math.cos(a1), ",", this._y1 = y + r * Math.sin(a1)
        );
      }
    },
    rect: function(x, y, w, h) {
      this._.push("M", this._x0 = this._x1 = +x, ",", this._y0 = this._y1 = +y, "h", +w, "v", +h, "h", -w, "Z");
    },
    toString: function() {
      return this._.join("");
    }
  };

  var version = "0.1.2";

  exports.version = version;
  exports.path = path;

}));
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-path')) :
  typeof define === 'function' && define.amd ? define('d3-shape', ['exports', 'd3-path'], factory) :
  factory((global.d3_shape = {}),global.d3_path);
}(this, function (exports,d3Path) { 'use strict';

  function constant(x) {
    return function constant() {
      return x;
    };
  };

  var pi = Math.PI;
  var halfPi = pi / 2;
  var tau = 2 * pi;

  function arcInnerRadius(d) {
    return d.innerRadius;
  }

  function arcOuterRadius(d) {
    return d.outerRadius;
  }

  function arcStartAngle(d) {
    return d.startAngle;
  }

  function arcEndAngle(d) {
    return d.endAngle;
  }

  function arcPadAngle(d) {
    return d && d.padAngle; // Note: optional!
  }

  function asin(x) {
    return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x);
  }

  function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
    var x10 = x1 - x0, y10 = y1 - y0,
        x32 = x3 - x2, y32 = y3 - y2,
        t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / (y32 * x10 - x32 * y10);
    return [x0 + t * x10, y0 + t * y10];
  }

  // Compute perpendicular offset line of length rc.
  // http://mathworld.wolfram.com/Circle-LineIntersection.html
  function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
    var x01 = x0 - x1,
        y01 = y0 - y1,
        lo = (cw ? rc : -rc) / Math.sqrt(x01 * x01 + y01 * y01),
        ox = lo * y01,
        oy = -lo * x01,
        x11 = x0 + ox,
        y11 = y0 + oy,
        x10 = x1 + ox,
        y10 = y1 + oy,
        x00 = (x11 + x10) / 2,
        y00 = (y11 + y10) / 2,
        dx = x10 - x11,
        dy = y10 - y11,
        d2 = dx * dx + dy * dy,
        r = r1 - rc,
        D = x11 * y10 - x10 * y11,
        d = (dy < 0 ? -1 : 1) * Math.sqrt(Math.max(0, r * r * d2 - D * D)),
        cx0 = (D * dy - dx * d) / d2,
        cy0 = (-D * dx - dy * d) / d2,
        cx1 = (D * dy + dx * d) / d2,
        cy1 = (-D * dx + dy * d) / d2,
        dx0 = cx0 - x00,
        dy0 = cy0 - y00,
        dx1 = cx1 - x00,
        dy1 = cy1 - y00;

    // Pick the closer of the two intersection points.
    // TODO Is there a faster way to determine which intersection to use?
    if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;

    return {
      cx: cx0,
      cy: cy0,
      x01: -ox,
      y01: -oy,
      x11: cx0 * (r1 / r - 1),
      y11: cy0 * (r1 / r - 1)
    };
  }

  function arc() {
    var innerRadius = arcInnerRadius,
        outerRadius = arcOuterRadius,
        cornerRadius = constant(0),
        padRadius = null,
        startAngle = arcStartAngle,
        endAngle = arcEndAngle,
        padAngle = arcPadAngle,
        context = null,
        output = null;

    function arc() {
      var buffer,
          r,
          r0 = +innerRadius.apply(this, arguments),
          r1 = +outerRadius.apply(this, arguments),
          a0 = startAngle.apply(this, arguments) - halfPi,
          a1 = endAngle.apply(this, arguments) - halfPi,
          da = Math.abs(a1 - a0),
          cw = a1 > a0;

      if (!context) context = buffer = d3Path.path();

      // Ensure that the outer radius is always larger than the inner radius.
      if (r1 < r0) r = r1, r1 = r0, r0 = r;

      // Is it a point?
      if (!(r1 > 0)) context.moveTo(0, 0);

      // Or is it a circle or annulus?
      else if (da >= tau) {
        context.moveTo(r1 * Math.cos(a0), r1 * Math.sin(a0));
        context.arc(0, 0, r1, a0, a1, !cw);
        if (r0 > 0) {
          context.moveTo(r0 * Math.cos(a1), r0 * Math.sin(a1));
          context.arc(0, 0, r0, a1, a0, cw);
        }
      }

      // Or is it a circular or annular sector?
      else {
        var a01 = a0,
            a11 = a1,
            a00 = a0,
            a10 = a1,
            da0 = da,
            da1 = da,
            ap = padAngle.apply(this, arguments) / 2,
            rp = (ap > 0) && (padRadius ? +padRadius.apply(this, arguments) : Math.sqrt(r0 * r0 + r1 * r1)),
            rc = Math.min(Math.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
            rc0 = rc,
            rc1 = rc;

        // Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
        if (rp > 0) {
          var p0 = asin(rp / r0 * Math.sin(ap)),
              p1 = asin(rp / r1 * Math.sin(ap));
          if ((da0 -= p0 * 2) > 0) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
          else da0 = 0, a00 = a10 = (a0 + a1) / 2;
          if ((da1 -= p1 * 2) > 0) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
          else da1 = 0, a01 = a11 = (a0 + a1) / 2;
        }

        var x01 = r1 * Math.cos(a01),
            y01 = r1 * Math.sin(a01),
            x10 = r0 * Math.cos(a10),
            y10 = r0 * Math.sin(a10);

        // Apply rounded corners?
        if (rc > 0) {
          var x11 = r1 * Math.cos(a11),
              y11 = r1 * Math.sin(a11),
              x00 = r0 * Math.cos(a00),
              y00 = r0 * Math.sin(a00);

          // Restrict the corner radius according to the sector angle.
          if (da < pi) {
            var oc = da0 > 0 ? intersect(x01, y01, x00, y00, x11, y11, x10, y10) : [x10, y10],
                ax = x01 - oc[0],
                ay = y01 - oc[1],
                bx = x11 - oc[0],
                by = y11 - oc[1],
                kc = 1 / Math.sin(Math.acos((ax * bx + ay * by) / (Math.sqrt(ax * ax + ay * ay) * Math.sqrt(bx * bx + by * by))) / 2),
                lc = Math.sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
            rc0 = Math.min(rc, (r0 - lc) / (kc - 1));
            rc1 = Math.min(rc, (r1 - lc) / (kc + 1));
          }
        }

        // Is the sector collapsed to a line?
        if (!(da1 > 0)) context.moveTo(x01, y01);

        // Does the sector’s outer ring have rounded corners?
        else if (rc1 > 0) {
          var t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw),
              t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);

          context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);

          // Have the corners merged?
          if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, Math.atan2(t0.y01, t0.x01), Math.atan2(t1.y01, t1.x01), !cw);

          // Otherwise, draw the two corners and the ring.
          else {
            context.arc(t0.cx, t0.cy, rc1, Math.atan2(t0.y01, t0.x01), Math.atan2(t0.y11, t0.x11), !cw);
            context.arc(0, 0, r1, Math.atan2(t0.cy + t0.y11, t0.cx + t0.x11), Math.atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
            context.arc(t1.cx, t1.cy, rc1, Math.atan2(t1.y11, t1.x11), Math.atan2(t1.y01, t1.x01), !cw);
          }
        }

        // Or is the outer ring just a circular arc?
        else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);

        // Is there no inner ring, and it’s a circular sector?
        // Or perhaps it’s an annular sector collapsed due to padding?
        if (!(r0 > 0) || !(da0 > 0)) context.lineTo(x10, y10);

        // Does the sector’s inner ring (or point) have rounded corners?
        else if (rc0 > 0) {
          var t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw),
              t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);

          context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);

          // Have the corners merged?
          if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, Math.atan2(t0.y01, t0.x01), Math.atan2(t1.y01, t1.x01), !cw);

          // Otherwise, draw the two corners and the ring.
          else {
            context.arc(t0.cx, t0.cy, rc0, Math.atan2(t0.y01, t0.x01), Math.atan2(t0.y11, t0.x11), !cw);
            context.arc(0, 0, r0, Math.atan2(t0.cy + t0.y11, t0.cx + t0.x11), Math.atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);
            context.arc(t1.cx, t1.cy, rc0, Math.atan2(t1.y11, t1.x11), Math.atan2(t1.y01, t1.x01), !cw);
          }
        }

        // Or is the inner ring just a circular arc?
        else context.arc(0, 0, r0, a10, a00, cw);
      }

      context.closePath();

      if (buffer) return context = null, buffer + "" || null;
    }

    arc.centroid = function() {
      var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
          a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi / 2;
      return [Math.cos(a) * r, Math.sin(a) * r];
    };

    arc.innerRadius = function(_) {
      return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant(+_), arc) : innerRadius;
    };

    arc.outerRadius = function(_) {
      return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant(+_), arc) : outerRadius;
    };

    arc.cornerRadius = function(_) {
      return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant(+_), arc) : cornerRadius;
    };

    arc.padRadius = function(_) {
      return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant(+_), arc) : padRadius;
    };

    arc.startAngle = function(_) {
      return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant(+_), arc) : startAngle;
    };

    arc.endAngle = function(_) {
      return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant(+_), arc) : endAngle;
    };

    arc.padAngle = function(_) {
      return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant(+_), arc) : padAngle;
    };

    arc.context = function(_) {
      return arguments.length ? ((context = output = _ == null ? null : _), arc) : context;
    };

    return arc;
  };

  var slice = Array.prototype.slice;

  function bind(curve, args) {
    if (args.length < 2) return curve;
    args = slice.call(args);
    args[0] = null;
    return function(context) {
      args[0] = context;
      return curve.apply(null, args);
    };
  };

  function Linear(context) {
    this._context = context;
  }

  Linear.prototype = {
    areaStart: function() {
      this._line = 0;
    },
    areaEnd: function() {
      this._line = NaN;
    },
    lineStart: function() {
      this._point = 0;
    },
    lineEnd: function() {
      if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
      this._line = 1 - this._line;
    },
    point: function(x, y) {
      x = +x, y = +y;
      switch (this._point) {
        case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
        case 1: this._point = 2; // proceed
        default: this._context.lineTo(x, y); break;
      }
    }
  };

  function curveLinear(context) {
    return new Linear(context);
  };

  function x(p) {
    return p[0];
  };

  function y(p) {
    return p[1];
  };

  function area() {
    var x0 = x,
        x1 = null,
        y0 = constant(0),
        y1 = y,
        defined = constant(true),
        context = null,
        curve = curveLinear,
        output = null;

    function area(data) {
      var i,
          j,
          k,
          n = data.length,
          d,
          defined0 = false,
          buffer,
          x0z = new Array(n),
          y0z = new Array(n);

      if (!context) output = curve(buffer = d3Path.path());

      for (i = 0; i <= n; ++i) {
        if (!(i < n && defined(d = data[i], i, data)) === defined0) {
          if (defined0 = !defined0) {
            j = i;
            output.areaStart();
            output.lineStart();
          } else {
            output.lineEnd();
            output.lineStart();
            for (k = i - 1; k >= j; --k) {
              output.point(x0z[k], y0z[k]);
            }
            output.lineEnd();
            output.areaEnd();
          }
        }
        if (defined0) {
          x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);
          output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);
        }
      }

      if (buffer) return output = null, buffer + "" || null;
    }

    area.x = function(_) {
      return arguments.length ? (x0 = typeof _ === "function" ? _ : constant(+_), x1 = null, area) : x0;
    };

    area.x0 = function(_) {
      return arguments.length ? (x0 = typeof _ === "function" ? _ : constant(+_), area) : x0;
    };

    area.x1 = function(_) {
      return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant(+_), area) : x1;
    };

    area.y = function(_) {
      return arguments.length ? (y0 = typeof _ === "function" ? _ : constant(+_), y1 = null, area) : y0;
    };

    area.y0 = function(_) {
      return arguments.length ? (y0 = typeof _ === "function" ? _ : constant(+_), area) : y0;
    };

    area.y1 = function(_) {
      return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant(+_), area) : y1;
    };

    area.defined = function(_) {
      return arguments.length ? (defined = typeof _ === "function" ? _ : constant(!!_), area) : defined;
    };

    area.curve = function(_) {
      return arguments.length ? (curve = bind(_, arguments), context != null && (output = curve(context)), area) : curve;
    };

    area.context = function(_) {
      return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;
    };

    return area;
  };

  function noop() {};

  function point(that, x, y) {
    that._context.bezierCurveTo(
      (2 * that._x0 + that._x1) / 3,
      (2 * that._y0 + that._y1) / 3,
      (that._x0 + 2 * that._x1) / 3,
      (that._y0 + 2 * that._y1) / 3,
      (that._x0 + 4 * that._x1 + x) / 6,
      (that._y0 + 4 * that._y1 + y) / 6
    );
  };

  function Basis(context) {
    this._context = context;
  }

  Basis.prototype = {
    areaStart: function() {
      this._line = 0;
    },
    areaEnd: function() {
      this._line = NaN;
    },
    lineStart: function() {
      this._x0 = this._x1 =
      this._y0 = this._y1 = NaN;
      this._point = 0;
    },
    lineEnd: function() {
      switch (this._point) {
        case 3: point(this, this._x1, this._y1); // proceed
        case 2: this._context.lineTo(this._x1, this._y1); break;
      }
      if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
      this._line = 1 - this._line;
    },
    point: function(x, y) {
      x = +x, y = +y;
      switch (this._point) {
        case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
        case 1: this._point = 2; break;
        case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed
        default: point(this, x, y); break;
      }
      this._x0 = this._x1, this._x1 = x;
      this._y0 = this._y1, this._y1 = y;
    }
  };

  function basis(context) {
    return new Basis(context);
  };

  function BasisClosed(context) {
    this._context = context;
  }

  BasisClosed.prototype = {
    areaStart: noop,
    areaEnd: noop,
    lineStart: function() {
      this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =
      this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;
      this._point = 0;
    },
    lineEnd: function() {
      switch (this._point) {
        case 1: {
          this._context.moveTo(this._x2, this._y2);
          this._context.closePath();
          break;
        }
        case 2: {
          this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);
          this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);
          this._context.closePath();
          break;
        }
        case 3: {
          this.point(this._x2, this._y2);
          this.point(this._x3, this._y3);
          this.point(this._x4, this._y4);
          break;
        }
      }
    },
    point: function(x, y) {
      x = +x, y = +y;
      switch (this._point) {
        case 0: this._point = 1; this._x2 = x, this._y2 = y; break;
        case 1: this._point = 2; this._x3 = x, this._y3 = y; break;
        case 2: this._point = 3; this._x4 = x, this._y4 = y; this._context.moveTo((this._x0 + 4 * this._x1 + x) / 6, (this._y0 + 4 * this._y1 + y) / 6); break;
        default: point(this, x, y); break;
      }
      this._x0 = this._x1, this._x1 = x;
      this._y0 = this._y1, this._y1 = y;
    }
  };

  function basisClosed(context) {
    return new BasisClosed(context);
  };

  function BasisOpen(context) {
    this._context = context;
  }

  BasisOpen.prototype = {
    areaStart: function() {
      this._line = 0;
    },
    areaEnd: function() {
      this._line = NaN;
    },
    lineStart: function() {
      this._x0 = this._x1 =
      this._y0 = this._y1 = NaN;
      this._point = 0;
    },
    lineEnd: function() {
      if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
      this._line = 1 - this._line;
    },
    point: function(x, y) {
      x = +x, y = +y;
      switch (this._point) {
        case 0: this._point = 1; break;
        case 1: this._point = 2; break;
        case 2: this._point = 3; var x0 = (this._x0 + 4 * this._x1 + x) / 6, y0 = (this._y0 + 4 * this._y1 + y) / 6; this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); break;
        case 3: this._point = 4; // proceed
        default: point(this, x, y); break;
      }
      this._x0 = this._x1, this._x1 = x;
      this._y0 = this._y1, this._y1 = y;
    }
  };

  function basisOpen(context) {
    return new BasisOpen(context);
  };

  function Bundle(context, beta) {
    this._basis = basis(context);
    this._beta = beta;
  }

  Bundle.prototype = {
    lineStart: function() {
      this._x = [];
      this._y = [];
      this._basis.lineStart();
    },
    lineEnd: function() {
      var x = this._x,
          y = this._y,
          j = x.length - 1;

      if (j > 0) {
        var x0 = x[0],
            y0 = y[0],
            dx = x[j] - x0,
            dy = y[j] - y0,
            i = -1,
            t;

        while (++i <= j) {
          t = i / j;
          this._basis.point(
            this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),
            this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)
          );
        }
      }

      this._x = this._y = null;
      this._basis.lineEnd();
    },
    point: function(x, y) {
      this._x.push(+x);
      this._y.push(+y);
    }
  };

  function bundle(context, beta) {
    return beta == null ? new Bundle(context, 0.85)
        : (beta = +beta) === 1 ? basis(context)
        : new Bundle(context, beta);
  };

  function point$1(that, x, y) {
    that._context.bezierCurveTo(
      that._x1 + that._k * (that._x2 - that._x0),
      that._y1 + that._k * (that._y2 - that._y0),
      that._x2 + that._k * (that._x1 - x),
      that._y2 + that._k * (that._y1 - y),
      that._x2,
      that._y2
    );
  };

  function Cardinal(context, k) {
    this._context = context;
    this._k = k;
  }

  Cardinal.prototype = {
    areaStart: function() {
      this._line = 0;
    },
    areaEnd: function() {
      this._line = NaN;
    },
    lineStart: function() {
      this._x0 = this._x1 = this._x2 =
      this._y0 = this._y1 = this._y2 = NaN;
      this._point = 0;
    },
    lineEnd: function() {
      switch (this._point) {
        case 2: this._context.lineTo(this._x2, this._y2); break;
        case 3: point$1(this, this._x1, this._y1); break;
      }
      if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
      this._line = 1 - this._line;
    },
    point: function(x, y) {
      x = +x, y = +y;
      switch (this._point) {
        case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
        case 1: this._point = 2; this._x1 = x, this._y1 = y; break;
        case 2: this._point = 3; // proceed
        default: point$1(this, x, y); break;
      }
      this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
      this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
    }
  };

  function cardinal(context, tension) {
    return new Cardinal(context, (tension == null ? 1 : 1 - tension) / 6);
  };

  function CardinalClosed(context, k) {
    this._context = context;
    this._k = k;
  }

  CardinalClosed.prototype = {
    areaStart: noop,
    areaEnd: noop,
    lineStart: function() {
      this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
      this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
      this._point = 0;
    },
    lineEnd: function() {
      switch (this._point) {
        case 1: {
          this._context.moveTo(this._x3, this._y3);
          this._context.closePath();
          break;
        }
        case 2: {
          this._context.lineTo(this._x3, this._y3);
          this._context.closePath();
          break;
        }
        case 3: {
          this.point(this._x3, this._y3);
          this.point(this._x4, this._y4);
          this.point(this._x5, this._y5);
          break;
        }
      }
    },
    point: function(x, y) {
      x = +x, y = +y;
      switch (this._point) {
        case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
        case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
        case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
        default: point$1(this, x, y); break;
      }
      this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
      this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
    }
  };

  function cardinalClosed(context, tension) {
    return new CardinalClosed(context, (tension == null ? 1 : 1 - tension) / 6);
  };

  function CardinalOpen(context, k) {
    this._context = context;
    this._k = k;
  }

  CardinalOpen.prototype = {
    areaStart: function() {
      this._line = 0;
    },
    areaEnd: function() {
      this._line = NaN;
    },
    lineStart: function() {
      this._x0 = this._x1 = this._x2 =
      this._y0 = this._y1 = this._y2 = NaN;
      this._point = 0;
    },
    lineEnd: function() {
      if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
      this._line = 1 - this._line;
    },
    point: function(x, y) {
      x = +x, y = +y;
      switch (this._point) {
        case 0: this._point = 1; break;
        case 1: this._point = 2; break;
        case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
        case 3: this._point = 4; // proceed
        default: point$1(this, x, y); break;
      }
      this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
      this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
    }
  };

  function cardinalOpen(context, tension) {
    return new CardinalOpen(context, (tension == null ? 1 : 1 - tension) / 6);
  };

  var epsilon = 1e-6;

  function point$2(that, x, y) {
    var x1 = that._x1,
        y1 = that._y1,
        x2 = that._x2,
        y2 = that._y2;

    if (that._l01_a > epsilon) {
      var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,
          n = 3 * that._l01_a * (that._l01_a + that._l12_a);
      x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;
      y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;
    }

    if (that._l23_a > epsilon) {
      var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,
          m = 3 * that._l23_a * (that._l23_a + that._l12_a);
      x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;
      y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;
    }

    that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);
  };

  function CatmullRom(context, alpha) {
    this._context = context;
    this._alpha = alpha;
  }

  CatmullRom.prototype = {
    areaStart: function() {
      this._line = 0;
    },
    areaEnd: function() {
      this._line = NaN;
    },
    lineStart: function() {
      this._x0 = this._x1 = this._x2 =
      this._y0 = this._y1 = this._y2 = NaN;
      this._l01_a = this._l12_a = this._l23_a =
      this._l01_2a = this._l12_2a = this._l23_2a =
      this._point = 0;
    },
    lineEnd: function() {
      switch (this._point) {
        case 2: this._context.lineTo(this._x2, this._y2); break;
        case 3: this.point(this, this._x2, this._y2); break;
      }
      if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
      this._line = 1 - this._line;
    },
    point: function(x, y) {
      x = +x, y = +y;

      if (this._point) {
        var x23 = this._x2 - x,
            y23 = this._y2 - y;
        this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
      }

      switch (this._point) {
        case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
        case 1: this._point = 2; break;
        case 2: this._point = 3; // proceed
        default: point$2(this, x, y); break;
      }

      this._l01_a = this._l12_a, this._l12_a = this._l23_a;
      this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
      this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
      this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
    }
  };

  function catmullRom(context, alpha) {
    return (alpha = alpha == null ? 0.5 : +alpha)
        ? new CatmullRom(context, alpha)
        : cardinal(context, 0);
  };

  function CatmullRomClosed(context, alpha) {
    this._context = context;
    this._alpha = alpha;
  }

  CatmullRomClosed.prototype = {
    areaStart: noop,
    areaEnd: noop,
    lineStart: function() {
      this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
      this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
      this._l01_a = this._l12_a = this._l23_a =
      this._l01_2a = this._l12_2a = this._l23_2a =
      this._point = 0;
    },
    lineEnd: function() {
      switch (this._point) {
        case 1: {
          this._context.moveTo(this._x3, this._y3);
          this._context.closePath();
          break;
        }
        case 2: {
          this._context.lineTo(this._x3, this._y3);
          this._context.closePath();
          break;
        }
        case 3: {
          this.point(this._x3, this._y3);
          this.point(this._x4, this._y4);
          this.point(this._x5, this._y5);
          break;
        }
      }
    },
    point: function(x, y) {
      x = +x, y = +y;

      if (this._point) {
        var x23 = this._x2 - x,
            y23 = this._y2 - y;
        this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
      }

      switch (this._point) {
        case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
        case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
        case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
        default: point$2(this, x, y); break;
      }

      this._l01_a = this._l12_a, this._l12_a = this._l23_a;
      this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
      this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
      this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
    }
  };

  function catmullRomClosed(context, alpha) {
    return (alpha = alpha == null ? 0.5 : +alpha)
        ? new CatmullRomClosed(context, alpha)
        : cardinalClosed(context, 0);
  };

  function CatmullRomOpen(context, alpha) {
    this._context = context;
    this._alpha = alpha;
  }

  CatmullRomOpen.prototype = {
    areaStart: function() {
      this._line = 0;
    },
    areaEnd: function() {
      this._line = NaN;
    },
    lineStart: function() {
      this._x0 = this._x1 = this._x2 =
      this._y0 = this._y1 = this._y2 = NaN;
      this._l01_a = this._l12_a = this._l23_a =
      this._l01_2a = this._l12_2a = this._l23_2a =
      this._point = 0;
    },
    lineEnd: function() {
      if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
      this._line = 1 - this._line;
    },
    point: function(x, y) {
      x = +x, y = +y;

      if (this._point) {
        var x23 = this._x2 - x,
            y23 = this._y2 - y;
        this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
      }

      switch (this._point) {
        case 0: this._point = 1; break;
        case 1: this._point = 2; break;
        case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
        case 3: this._point = 4; // proceed
        default: point$2(this, x, y); break;
      }

      this._l01_a = this._l12_a, this._l12_a = this._l23_a;
      this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
      this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
      this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
    }
  };

  function catmullRomOpen(context, alpha) {
    return (alpha = alpha == null ? 0.5 : +alpha)
        ? new CatmullRomOpen(context, alpha)
        : cardinalOpen(context, 0);
  };

  var circle = {
    draw: function(context, size) {
      var r = Math.sqrt(size / pi);
      context.moveTo(r, 0);
      context.arc(0, 0, r, 0, tau);
    }
  };

  var cross = {
    draw: function(context, size) {
      var r = Math.sqrt(size / 5) / 2;
      context.moveTo(-3 * r, -r);
      context.lineTo(-r, -r);
      context.lineTo(-r, -3 * r);
      context.lineTo(r, -3 * r);
      context.lineTo(r, -r);
      context.lineTo(3 * r, -r);
      context.lineTo(3 * r, r);
      context.lineTo(r, r);
      context.lineTo(r, 3 * r);
      context.lineTo(-r, 3 * r);
      context.lineTo(-r, r);
      context.lineTo(-3 * r, r);
      context.closePath();
    }
  };

  var tan30 = Math.sqrt(1 / 3);
  var tan30_2 = tan30 * 2;
  var diamond = {
    draw: function(context, size) {
      var y = Math.sqrt(size / tan30_2),
          x = y * tan30;
      context.moveTo(0, -y);
      context.lineTo(x, 0);
      context.lineTo(0, y);
      context.lineTo(-x, 0);
      context.closePath();
    }
  };

  function LinearClosed(context) {
    this._context = context;
  }

  LinearClosed.prototype = {
    areaStart: noop,
    areaEnd: noop,
    lineStart: function() {
      this._point = 0;
    },
    lineEnd: function() {
      if (this._point) this._context.closePath();
    },
    point: function(x, y) {
      x = +x, y = +y;
      if (this._point) this._context.lineTo(x, y);
      else this._point = 1, this._context.moveTo(x, y);
    }
  };

  function linearClosed(context) {
    return new LinearClosed(context);
  };

  function line() {
    var x$$ = x,
        y$$ = y,
        defined = constant(true),
        context = null,
        curve = curveLinear,
        output = null;

    function line(data) {
      var i,
          n = data.length,
          d,
          defined0 = false,
          buffer;

      if (!context) output = curve(buffer = d3Path.path());

      for (i = 0; i <= n; ++i) {
        if (!(i < n && defined(d = data[i], i, data)) === defined0) {
          if (defined0 = !defined0) output.lineStart();
          else output.lineEnd();
        }
        if (defined0) output.point(+x$$(d, i, data), +y$$(d, i, data));
      }

      if (buffer) return output = null, buffer + "" || null;
    }

    line.x = function(_) {
      return arguments.length ? (x$$ = typeof _ === "function" ? _ : constant(+_), line) : x$$;
    };

    line.y = function(_) {
      return arguments.length ? (y$$ = typeof _ === "function" ? _ : constant(+_), line) : y$$;
    };

    line.defined = function(_) {
      return arguments.length ? (defined = typeof _ === "function" ? _ : constant(!!_), line) : defined;
    };

    line.curve = function(_) {
      return arguments.length ? (curve = bind(_, arguments), context != null && (output = curve(context)), line) : curve;
    };

    line.context = function(_) {
      return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;
    };

    return line;
  };

  function sign(x) {
    return x < 0 ? -1 : 1;
  }

  // Calculate the slopes of the tangents (Hermite-type interpolation) based on
  // the following paper: Steffen, M. 1990. A Simple Method for Monotonic
  // Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.
  // NOV(II), P. 443, 1990.
  function slope3(that, x2, y2) {
    var h0 = that._x1 - that._x0,
        h1 = x2 - that._x1,
        s0 = (that._y1 - that._y0) / h0,
        s1 = (y2 - that._y1) / h1,
        p = (s0 * h1 + s1 * h0) / (h0 + h1);
    return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
  }

  // Calculate a one-sided slope.
  function slope2(that, t) {
    var h = that._x1 - that._x0;
    return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;
  }

  // According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations
  // "you can express cubic Hermite interpolation in terms of cubic Bézier curves
  // with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1".
  function point$3(that, t0, t1) {
    var x0 = that._x0,
        y0 = that._y0,
        x1 = that._x1,
        y1 = that._y1,
        dx = (x1 - x0) / 3;
    that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);
  }

  function Monotone(context) {
    this._context = context;
  }

  Monotone.prototype = {
    areaStart: function() {
      this._line = 0;
    },
    areaEnd: function() {
      this._line = NaN;
    },
    lineStart: function() {
      this._x0 = this._x1 =
      this._y0 = this._y1 =
      this._t0 = NaN;
      this._point = 0;
    },
    lineEnd: function() {
      switch (this._point) {
        case 2: this._context.lineTo(this._x1, this._y1); break;
        case 3: point$3(this, this._t0, slope2(this, this._t0)); break;
      }
      if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
      this._line = 1 - this._line;
    },
    point: function(x, y) {
      var t1 = NaN;

      x = +x, y = +y;
      if (x === this._x1 && y === this._y1) return; // Ignore coincident points.
      switch (this._point) {
        case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
        case 1: this._point = 2; break;
        case 2: this._point = 3; point$3(this, slope2(this, t1 = slope3(this, x, y)), t1); break;
        default: point$3(this, this._t0, t1 = slope3(this, x, y)); break;
      }

      this._x0 = this._x1, this._x1 = x;
      this._y0 = this._y1, this._y1 = y;
      this._t0 = t1;
    }
  }

  function monotone(context) {
    return new Monotone(context);
  };

  function Natural(context) {
    this._context = context;
  }

  Natural.prototype = {
    areaStart: function() {
      this._line = 0;
    },
    areaEnd: function() {
      this._line = NaN;
    },
    lineStart: function() {
      this._x = [];
      this._y = [];
    },
    lineEnd: function() {
      var x = this._x,
          y = this._y,
          n = x.length;

      if (n) {
        this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);
        if (n === 2) {
          this._context.lineTo(x[1], y[1]);
        } else {
          var px = controlPoints(x),
              py = controlPoints(y);
          for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {
            this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);
          }
        }
      }

      if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();
      this._line = 1 - this._line;
      this._x = this._y = null;
    },
    point: function(x, y) {
      this._x.push(+x);
      this._y.push(+y);
    }
  };

  // See https://www.particleincell.com/2012/bezier-splines/ for derivation.
  function controlPoints(x) {
    var i,
        n = x.length - 1,
        m,
        a = new Array(n),
        b = new Array(n),
        r = new Array(n);
    a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];
    for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];
    a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];
    for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];
    a[n - 1] = r[n - 1] / b[n - 1];
    for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];
    b[n - 1] = (x[n] + a[n - 1]) / 2;
    for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];
    return [a, b];
  }

  function natural(context) {
    return new Natural(context);
  };

  function descending(a, b) {
    return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
  };

  function identity(d) {
    return d;
  };

  function pie() {
    var value = identity,
        sortValues = descending,
        sort = null,
        startAngle = constant(0),
        endAngle = constant(tau),
        padAngle = constant(0);

    function pie(data) {
      var n = data.length,
          sum = 0,
          index = new Array(n),
          arcs = new Array(n),
          a0 = +startAngle.apply(this, arguments),
          da = Math.min(tau, Math.max(-tau, endAngle.apply(this, arguments) - a0)),
          a1,
          p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)),
          pa = p * (da < 0 ? -1 : 1);

      for (var i = 0, v; i < n; ++i) {
        if ((v = arcs[index[i] = i] = +value(data[i], i, data)) > 0) {
          sum += v;
        }
      }

      // Optionally sort the arcs by previously-computed values or by data.
      if (sortValues != null) index.sort(function(i, j) { return sortValues(arcs[i], arcs[j]); });
      else if (sort !== null) index.sort(function(i, j) { return sort(data[i], data[j]); });

      // Compute the arcs! They are stored in the original data's order.
      for (var i = 0, j, k = sum ? (da - n * pa) / sum : 0; i < n; ++i, a0 = a1) {
        j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
          data: data[j],
          value: v,
          startAngle: a0,
          endAngle: a1,
          padAngle: p
        };
      }

      return arcs;
    }

    pie.value = function(_) {
      return arguments.length ? (value = typeof _ === "function" ? _ : constant(+_), pie) : value;
    };

    pie.sortValues = function(_) {
      return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
    };

    pie.sort = function(_) {
      return arguments.length ? (sort = _, sortValues = null, pie) : sort;
    };

    pie.startAngle = function(_) {
      return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant(+_), pie) : startAngle;
    };

    pie.endAngle = function(_) {
      return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant(+_), pie) : endAngle;
    };

    pie.padAngle = function(_) {
      return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant(+_), pie) : padAngle;
    };

    return pie;
  };

  function Radial(curve) {
    this._curve = curve;
  }

  Radial.prototype = {
    areaStart: function() {
      this._curve.areaStart();
    },
    areaEnd: function() {
      this._curve.areaEnd();
    },
    lineStart: function() {
      this._curve.lineStart();
    },
    lineEnd: function() {
      this._curve.lineEnd();
    },
    point: function(a, r) {
      a -= halfPi, this._curve.point(r * Math.cos(a), r * Math.sin(a));
    }
  };

  function curveRadial(curve, args) {
    curve = bind(curve, args);

    function radial(context) {
      return new Radial(curve(context));
    }

    radial._curve = curve;

    return radial;
  };

  function radialArea() {
    var a = area(),
        c = a.curve;

    a.angle = a.x, delete a.x;
    a.startAngle = a.x0, delete a.x0;
    a.endAngle = a.x1, delete a.x1;
    a.radius = a.y, delete a.y;
    a.innerRadius = a.y0, delete a.y0;
    a.outerRadius = a.y1, delete a.y1;

    a.curve = function(_) {
      return arguments.length ? c(curveRadial(_, arguments)) : c()._curve;
    };

    return a.curve(curveLinear);
  };

  function radialLine() {
    var l = line(),
        c = l.curve;

    l.angle = l.x, delete l.x;
    l.radius = l.y, delete l.y;

    l.curve = function(_) {
      return arguments.length ? c(curveRadial(_, arguments)) : c()._curve;
    };

    return l.curve(curveLinear);
  };

  var square = {
    draw: function(context, size) {
      var w = Math.sqrt(size),
          x = -w / 2;
      context.rect(x, x, w, w);
    }
  };

  var ka = 0.89081309152928522810;
  var kr = Math.sin(pi / 10) / Math.sin(7 * pi / 10);
  var kx = Math.sin(tau / 10) * kr;
  var ky = -Math.cos(tau / 10) * kr;
  var star = {
    draw: function(context, size) {
      var r = Math.sqrt(size * ka),
          x = kx * r,
          y = ky * r;
      context.moveTo(0, -r);
      context.lineTo(x, y);
      for (var i = 1; i < 5; ++i) {
        var a = tau * i / 5,
            c = Math.cos(a),
            s = Math.sin(a);
        context.lineTo(s * r, -c * r);
        context.lineTo(c * x - s * y, s * x + c * y);
      }
      context.closePath();
    }
  };

  function StepAfter(context) {
    this._context = context;
  }

  StepAfter.prototype = {
    areaStart: function() {
      this._line = 0;
    },
    areaEnd: function() {
      this._line = NaN;
    },
    lineStart: function() {
      this._y = NaN;
      this._point = 0;
    },
    lineEnd: function() {
      if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
      this._line = 1 - this._line;
    },
    point: function(x, y) {
      x = +x, y = +y;
      switch (this._point) {
        case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
        case 1: this._point = 2; // proceed
        default: {
          this._context.lineTo(x, this._y);
          this._context.lineTo(x, y);
          break;
        }
      }
      this._y = y;
    }
  };

  function stepAfter(context) {
    return new StepAfter(context);
  };

  function StepBefore(context) {
    this._context = context;
  }

  StepBefore.prototype = {
    areaStart: function() {
      this._line = 0;
    },
    areaEnd: function() {
      this._line = NaN;
    },
    lineStart: function() {
      this._x = NaN;
      this._point = 0;
    },
    lineEnd: function() {
      if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
      this._line = 1 - this._line;
    },
    point: function(x, y) {
      x = +x, y = +y;
      switch (this._point) {
        case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
        case 1: this._point = 2; // proceed
        default: {
          this._context.lineTo(this._x, y);
          this._context.lineTo(x, y);
          break;
        }
      }
      this._x = x;
    }
  };

  function stepBefore(context) {
    return new StepBefore(context);
  };

  function Step(context) {
    this._context = context;
  }

  Step.prototype = {
    areaStart: function() {
      this._line = 0;
    },
    areaEnd: function() {
      this._line = NaN;
    },
    lineStart: function() {
      this._x = this._y = NaN;
      this._point = 0;
    },
    lineEnd: function() {
      if (this._point === 2) this._context.lineTo(this._x, this._y);
      if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
      this._line = 1 - this._line;
    },
    point: function(x, y) {
      x = +x, y = +y;
      switch (this._point) {
        case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
        case 1: this._point = 2; // proceed
        default: {
          var x1 = (this._x + x) / 2;
          this._context.lineTo(x1, this._y);
          this._context.lineTo(x1, y);
          break;
        }
      }
      this._x = x, this._y = y;
    }
  };

  function step(context) {
    return new Step(context);
  };

  var c = -0.5;
  var s = Math.sqrt(3) / 2;
  var k = 1 / Math.sqrt(12);
  var a = (k / 2 + 1) * 3;
  var wye = {
    draw: function(context, size) {
      var r = Math.sqrt(size / a),
          x0 = r / 2,
          y0 = r * k,
          x1 = x0,
          y1 = r * k + r,
          x2 = -x1,
          y2 = y1;
      context.moveTo(x0, y0);
      context.lineTo(x1, y1);
      context.lineTo(x2, y2);
      context.lineTo(c * x0 - s * y0, s * x0 + c * y0);
      context.lineTo(c * x1 - s * y1, s * x1 + c * y1);
      context.lineTo(c * x2 - s * y2, s * x2 + c * y2);
      context.lineTo(c * x0 + s * y0, c * y0 - s * x0);
      context.lineTo(c * x1 + s * y1, c * y1 - s * x1);
      context.lineTo(c * x2 + s * y2, c * y2 - s * x2);
      context.closePath();
    }
  };

  var sqrt3 = Math.sqrt(3);

  var triangle = {
    draw: function(context, size) {
      var y = -Math.sqrt(size / (sqrt3 * 3));
      context.moveTo(0, y * 2);
      context.lineTo(-sqrt3 * y, -y);
      context.lineTo(sqrt3 * y, -y);
      context.closePath();
    }
  };

  var symbols = [
    circle,
    cross,
    diamond,
    square,
    star,
    triangle,
    wye
  ];

  function symbol() {
    var type = constant(circle),
        size = constant(64),
        context = null;

    function symbol() {
      var buffer;
      if (!context) context = buffer = d3Path.path();
      type.apply(this, arguments).draw(context, +size.apply(this, arguments));
      if (buffer) return context = null, buffer + "" || null;
    }

    symbol.type = function(_) {
      return arguments.length ? (type = typeof _ === "function" ? _ : constant(_), symbol) : type;
    };

    symbol.size = function(_) {
      return arguments.length ? (size = typeof _ === "function" ? _ : constant(+_), symbol) : size;
    };

    symbol.context = function(_) {
      return arguments.length ? (context = _ == null ? null : _, symbol) : context;
    };

    return symbol;
  };

  var version = "0.2.0";

  exports.version = version;
  exports.arc = arc;
  exports.area = area;
  exports.basisClosed = basisClosed;
  exports.basisOpen = basisOpen;
  exports.basis = basis;
  exports.bundle = bundle;
  exports.cardinalClosed = cardinalClosed;
  exports.cardinalOpen = cardinalOpen;
  exports.cardinal = cardinal;
  exports.catmullRomClosed = catmullRomClosed;
  exports.catmullRomOpen = catmullRomOpen;
  exports.catmullRom = catmullRom;
  exports.circle = circle;
  exports.cross = cross;
  exports.diamond = diamond;
  exports.linearClosed = linearClosed;
  exports.linear = curveLinear;
  exports.line = line;
  exports.monotone = monotone;
  exports.natural = natural;
  exports.pie = pie;
  exports.radialArea = radialArea;
  exports.radialLine = radialLine;
  exports.square = square;
  exports.star = star;
  exports.stepAfter = stepAfter;
  exports.stepBefore = stepBefore;
  exports.step = step;
  exports.symbol = symbol;
  exports.symbols = symbols;
  exports.triangle = triangle;
  exports.wye = wye;

}));
svg = d3.select('svg')
width = svg.node().getBoundingClientRect().width
height = svg.node().getBoundingClientRect().height

svg
 .attr
   viewBox: "#{-width/2} #{-height/2} #{width} #{height}"
    
OUTER_RADIUS = 200
INNER_RADIUS = 60
    
r_temp = d3.scale.linear()
  .domain([-20,40])
  .range([INNER_RADIUS,OUTER_RADIUS])
  
prec_radius = d3.scale.sqrt()
  .domain([0, 100])
  .range([0,32])
  
temp_color = d3.scale.linear()
  .domain([-20,0,20,40])
  .range([d3.hcl(290,70,15),d3.hcl(230,70,45),d3.hcl(80,70,75),d3.hcl(10,70,45)])
  .interpolate(d3.interpolateHcl)
  
arc_generator = d3_shape.arc()

# reference and labels
refs_data = d3.range(-20,40,10)
refs = svg.selectAll '.ref'
  .data refs_data
  
refs.enter().append 'circle'
  .attr
    class: 'ref'
    r: (d) -> r_temp(d)
    stroke: (d) -> if d is 0 then '#CCC' else '#EEE'
    
refs_labels_north = svg.selectAll '.ref_label_north'
  .data refs_data
  
refs_labels_north.enter().append 'text'
  .text (d) -> "#{d}°C"
  .attr
    class: 'ref_label_north'
    y: (d) -> -r_temp(d)
    dy: '0.35em'
    fill: (d) -> if d is 0 then '#BBB' else '#DDD'
    
refs_labels_south = svg.selectAll '.ref_label_south'
  .data refs_data
  
refs_labels_south.enter().append 'text'
  .text (d) -> "#{d}°C"
  .attr
    class: 'ref_label_south'
    y: (d) -> r_temp(d)
    dy: '0.35em'
    fill: (d) -> if d is 0 then '#BBB' else '#DDD'

svg.append 'circle'
  .attr
    class: 'prec_ref'
    r: OUTER_RADIUS
    
svg.append 'text'
  .text 'PISA'
  .attr
    class: 'title'
    dy: '0.35em'

d3.csv 'pisa_2014_weather.csv', (days) ->
  days.forEach (d) ->
    d['Min TemperatureC'] = +d['Min TemperatureC']
    d['Max TemperatureC'] = +d['Max TemperatureC']
    d['Mean TemperatureC'] = +d['Mean TemperatureC']
    d['Precipitationmm'] = +d['Precipitationmm']
    
  angle = d3.scale.ordinal()
    .domain(days.map (d) -> d['CET'])
    .range(d3.range(Math.PI/2, 2*Math.PI+Math.PI/2, 2*Math.PI/days.length))
    
  temp_bars = svg.selectAll '.temp_bar'
    .data days

  enter_temp_bars = temp_bars.enter().append 'path'
    .attr
      class: 'bar temp_bar'
      d: (d,i) -> arc_generator {
          innerRadius: r_temp(d['Min TemperatureC']),
          outerRadius: r_temp(d['Max TemperatureC']),
          startAngle: i*2*Math.PI/days.length, # FIXME index-based positioning, should be day-based
          endAngle: (i+1)*2*Math.PI/days.length
        }
      fill: (d) -> temp_color(d['Mean TemperatureC'])
      
  enter_temp_bars.append 'title'
    .text (d) -> "#{d3.time.format('%Y, %B %e')(new Date(d['CET']))}\nTemperature:\n  Min: #{d['Min TemperatureC']} °C\n  Max: #{d['Max TemperatureC']} °C\n  Mean: #{d['Mean TemperatureC']} °C"
  
  
  prec_bubbles = svg.selectAll '.prec_bubble'
    .data days.sort (a,b) -> d3.descending(a['Precipitationmm'], b['Precipitationmm']) # draw bubbles from largest to smallest (hover) FIXME this is ugly
    
  enter_prec_bubbles = prec_bubbles.enter().append 'circle'
    .attr
      class: 'prec_bubble'
      r: (d) -> prec_radius(d['Precipitationmm'])
      cx: (d) -> -(OUTER_RADIUS)*Math.cos(angle(d['CET'])) # FIXME day should be converted first to a date
      cy: (d) -> -(OUTER_RADIUS)*Math.sin(angle(d['CET'])) # FIXME bubbles should be centered on the day slice, not at the beginning
      
  enter_prec_bubbles.append 'title'
    .text (d) -> "#{d3.time.format('%Y, %B %e')(new Date(d['CET']))}\nPrecipitation: #{d['Precipitationmm']} mm"

  # draw the hand
  svg.append 'line'
    .attr
      class: 'hand'
      x1: 0
      x2: 0
      y1: -INNER_RADIUS+10
      y2: -OUTER_RADIUS-40
      
  svg.append 'text'
    .text '2014'
    .attr
      class: 'hand_label'
      x: 4
      y: -OUTER_RADIUS-40
      dy: '0.6em'
      
@font-face {
  font-family: "Lacuna";
  src: url("lacuna.ttf");
}
@font-face {
  font-family: "Antonio-Light";
  src: url("Antonio-Light.ttf");
}

body, html {
  padding: 0;
  margin: 0;
  width: 100%;
  height: 100%;
  font-family: sans-serif;
  font-size: 12px;
  overflow: hidden;
}
svg {
  width: 100%;
  height: 100%;
  background: white;
}

.bar {
  stroke-width: 0.5;
  stroke: white;
  fill-opacity: 0.8;
}
.bar:hover {
  fill-opacity: 1;
}

.ref, .prec_ref {
  fill: none;
}
.prec_ref {
  stroke: steelblue;
  opacity: 0.2;
}
.ref_label_north, .ref_label_south {
  text-anchor: middle;
  font-size: 8px;
  text-shadow: -1px -1px white, -1px 1px white, 1px 1px white, 1px -1px white, -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white;
  font-family: "Lacuna";
}

.prec_bubble {
  fill: steelblue;
  fill-opacity: 0.2;
}
.prec_bubble:hover {
  fill-opacity: 0.8;
}

.title {
  font-size: 32px;
  text-anchor: middle;
  text-shadow: -1px -1px white, -1px 1px white, 1px 1px white, 1px -1px white, -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white;
  fill: #999;
  font-family: "Antonio-Light";
}

.hand {
  stroke: #777;
  stroke-dasharray: 2 2;
  fill: none;
}
.hand_label {
  font-size: 9px;
  font-weight: bold;
  font-family: "Lacuna";
  fill: #555;
}
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Weather wheel</title>
    <link rel="stylesheet" href="index.css">
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script src="d3-path.js"></script>
    <script src="d3-shape.js"></script>
  </head>
  <body>
    <svg></svg>
    <script src="index.js"></script>
  </body>
</html>
// Generated by CoffeeScript 1.10.0
(function() {
  var INNER_RADIUS, OUTER_RADIUS, arc_generator, height, prec_radius, r_temp, refs, refs_data, refs_labels_north, refs_labels_south, svg, temp_color, width;

  svg = d3.select('svg');

  width = svg.node().getBoundingClientRect().width;

  height = svg.node().getBoundingClientRect().height;

  svg.attr({
    viewBox: (-width / 2) + " " + (-height / 2) + " " + width + " " + height
  });

  OUTER_RADIUS = 200;

  INNER_RADIUS = 60;

  r_temp = d3.scale.linear().domain([-20, 40]).range([INNER_RADIUS, OUTER_RADIUS]);

  prec_radius = d3.scale.sqrt().domain([0, 100]).range([0, 32]);

  temp_color = d3.scale.linear().domain([-20, 0, 20, 40]).range([d3.hcl(290, 70, 15), d3.hcl(230, 70, 45), d3.hcl(80, 70, 75), d3.hcl(10, 70, 45)]).interpolate(d3.interpolateHcl);

  arc_generator = d3_shape.arc();

  refs_data = d3.range(-20, 40, 10);

  refs = svg.selectAll('.ref').data(refs_data);

  refs.enter().append('circle').attr({
    "class": 'ref',
    r: function(d) {
      return r_temp(d);
    },
    stroke: function(d) {
      if (d === 0) {
        return '#CCC';
      } else {
        return '#EEE';
      }
    }
  });

  refs_labels_north = svg.selectAll('.ref_label_north').data(refs_data);

  refs_labels_north.enter().append('text').text(function(d) {
    return d + "°C";
  }).attr({
    "class": 'ref_label_north',
    y: function(d) {
      return -r_temp(d);
    },
    dy: '0.35em',
    fill: function(d) {
      if (d === 0) {
        return '#BBB';
      } else {
        return '#DDD';
      }
    }
  });

  refs_labels_south = svg.selectAll('.ref_label_south').data(refs_data);

  refs_labels_south.enter().append('text').text(function(d) {
    return d + "°C";
  }).attr({
    "class": 'ref_label_south',
    y: function(d) {
      return r_temp(d);
    },
    dy: '0.35em',
    fill: function(d) {
      if (d === 0) {
        return '#BBB';
      } else {
        return '#DDD';
      }
    }
  });

  svg.append('circle').attr({
    "class": 'prec_ref',
    r: OUTER_RADIUS
  });

  svg.append('text').text('PISA').attr({
    "class": 'title',
    dy: '0.35em'
  });

  d3.csv('pisa_2014_weather.csv', function(days) {
    var angle, enter_prec_bubbles, enter_temp_bars, prec_bubbles, temp_bars;
    days.forEach(function(d) {
      d['Min TemperatureC'] = +d['Min TemperatureC'];
      d['Max TemperatureC'] = +d['Max TemperatureC'];
      d['Mean TemperatureC'] = +d['Mean TemperatureC'];
      return d['Precipitationmm'] = +d['Precipitationmm'];
    });
    angle = d3.scale.ordinal().domain(days.map(function(d) {
      return d['CET'];
    })).range(d3.range(Math.PI / 2, 2 * Math.PI + Math.PI / 2, 2 * Math.PI / days.length));
    temp_bars = svg.selectAll('.temp_bar').data(days);
    enter_temp_bars = temp_bars.enter().append('path').attr({
      "class": 'bar temp_bar',
      d: function(d, i) {
        return arc_generator({
          innerRadius: r_temp(d['Min TemperatureC']),
          outerRadius: r_temp(d['Max TemperatureC']),
          startAngle: i * 2 * Math.PI / days.length,
          endAngle: (i + 1) * 2 * Math.PI / days.length
        });
      },
      fill: function(d) {
        return temp_color(d['Mean TemperatureC']);
      }
    });
    enter_temp_bars.append('title').text(function(d) {
      return (d3.time.format('%Y, %B %e')(new Date(d['CET']))) + "\nTemperature:\n  Min: " + d['Min TemperatureC'] + " °C\n  Max: " + d['Max TemperatureC'] + " °C\n  Mean: " + d['Mean TemperatureC'] + " °C";
    });
    prec_bubbles = svg.selectAll('.prec_bubble').data(days.sort(function(a, b) {
      return d3.descending(a['Precipitationmm'], b['Precipitationmm']);
    }));
    enter_prec_bubbles = prec_bubbles.enter().append('circle').attr({
      "class": 'prec_bubble',
      r: function(d) {
        return prec_radius(d['Precipitationmm']);
      },
      cx: function(d) {
        return -OUTER_RADIUS * Math.cos(angle(d['CET']));
      },
      cy: function(d) {
        return -OUTER_RADIUS * Math.sin(angle(d['CET']));
      }
    });
    enter_prec_bubbles.append('title').text(function(d) {
      return (d3.time.format('%Y, %B %e')(new Date(d['CET']))) + "\nPrecipitation: " + d['Precipitationmm'] + " mm";
    });
    svg.append('line').attr({
      "class": 'hand',
      x1: 0,
      x2: 0,
      y1: -INNER_RADIUS + 10,
      y2: -OUTER_RADIUS - 40
    });
    return svg.append('text').text('2014').attr({
      "class": 'hand_label',
      x: 4,
      y: -OUTER_RADIUS - 40,
      dy: '0.6em'
    });
  });

}).call(this);
File not shown (binary encoding).
CET,Max TemperatureC,Mean TemperatureC,Min TemperatureC,Dew PointC,MeanDew PointC,Min DewpointC,Max Humidity, Mean Humidity, Min Humidity, Max Sea Level PressurehPa, Mean Sea Level PressurehPa, Min Sea Level PressurehPa, Max VisibilityKm, Mean VisibilityKm, Min VisibilitykM, Max Wind SpeedKm/h, Mean Wind SpeedKm/h, Max Gust SpeedKm/h,Precipitationmm, CloudCover, Events,WindDirDegrees
2014-1-1,12,6,-2,7,3,-2,100,89,69,1021,1020,1019,14,10,5,16,8,,0.00,3,Fog,116
2014-1-2,9,7,4,8,7,3,100,90,71,1020,1016,1015,11,8,3,23,11,,12.95,6,Rain,110
2014-1-3,13,10,8,11,9,7,100,93,87,1021,1019,1016,10,4,0,11,6,,1.02,5,Fog-Rain,121
2014-1-4,14,12,10,12,11,9,94,89,80,1021,1015,1008,14,8,3,34,13,,1.02,6,Rain-Thunderstorm,148
2014-1-5,14,11,8,12,9,5,94,84,67,1012,1005,1000,26,8,3,29,18,,11.94,5,Rain-Thunderstorm,114
2014-1-6,15,9,3,9,6,2,96,88,56,1023,1019,1013,26,11,10,11,5,,0.00,,Fog,116
2014-1-7,13,8,3,11,6,3,100,91,75,1028,1025,1023,19,9,2,13,8,,0.00,1,Fog,118
2014-1-8,13,8,3,9,6,3,100,92,76,1030,1028,1027,10,6,0,11,6,,0.00,3,Fog,124
2014-1-9,14,10,6,10,7,4,94,88,73,1027,1024,1021,14,9,3,13,6,,0.00,4,Fog,134
2014-1-10,14,10,7,10,8,7,94,88,75,1022,1021,1020,19,10,8,13,6,,0.00,5,,119
2014-1-11,14,11,7,9,8,6,94,87,68,1023,1022,1021,19,10,8,14,6,,0.00,5,,102
2014-1-12,15,10,5,10,8,5,100,89,71,1024,1022,1021,14,9,0,13,6,,0.00,4,Fog,122
2014-1-13,11,8,4,8,6,3,100,92,80,1022,1018,1012,10,5,0,21,8,,2.03,5,Fog-Rain,117
2014-1-14,12,10,8,10,8,6,94,84,66,1013,1007,1005,14,9,4,24,16,,10.92,5,Rain,221
2014-1-15,13,9,6,9,7,5,100,87,64,1016,1011,1007,26,10,8,21,10,,0.00,4,Fog-Rain,134
2014-1-16,11,8,4,9,7,4,94,89,79,1017,1015,1014,19,10,8,16,10,,0.51,4,Fog-Rain,120
2014-1-17,13,12,10,12,11,9,94,89,74,1014,1010,1008,14,8,5,26,16,,19.05,6,Rain,136
2014-1-18,14,12,11,11,11,9,94,90,82,1010,1007,1003,10,8,3,23,13,,12.95,6,Rain-Thunderstorm,101
2014-1-19,14,12,10,12,11,9,94,89,79,1004,1001,998,10,9,6,24,11,32,3.05,5,Rain-Hail-Thunderstorm,117
2014-1-20,14,12,9,11,10,8,94,89,68,1001,999,999,14,10,3,21,10,,0.00,5,Rain,110
2014-1-21,15,10,6,11,8,6,100,87,72,1009,1004,1000,14,10,8,14,5,,0.00,4,Fog,175
2014-1-22,13,9,5,10,8,4,100,82,59,1015,1012,1009,19,10,8,55,14,,0.00,4,Fog,273
2014-1-23,11,7,3,9,6,3,100,90,72,1017,1015,1013,14,9,5,24,10,,0.76,5,Rain,91
2014-1-24,10,7,4,8,6,3,100,88,67,1013,1006,1003,10,7,0,13,8,,0.00,5,Fog-Rain,74
2014-1-25,12,7,1,4,2,-1,100,75,32,1012,1009,1005,31,12,10,21,8,,0.00,1,,114
2014-1-26,14,7,0,5,2,-1,93,77,26,1012,1009,1006,31,12,10,19,8,,0.00,2,,126
2014-1-27,8,6,3,7,4,1,100,88,61,1007,999,996,14,10,5,23,11,,3.05,5,Rain,110
2014-1-28,10,6,1,4,2,0,100,85,44,1000,998,996,19,9,3,21,8,,0.00,2,Fog,120
2014-1-29,10,5,0,7,3,-1,100,83,46,1005,1002,1000,14,10,10,32,14,,0.00,5,Rain,90
2014-1-30,12,9,5,11,8,4,94,92,80,1006,1004,1002,10,7,2,37,14,,18.03,6,Rain,104
2014-1-31,11,10,9,10,9,7,94,91,85,1012,1008,1003,14,9,6,37,14,,0.51,6,Rain,113
2014-2-1,14,11,7,11,9,7,94,88,72,1010,1008,1005,14,9,5,26,8,40,2.03,6,Rain,122
2014-2-2,12,10,8,9,8,7,94,90,65,1009,1007,1006,19,10,0,11,5,,1.02,5,Fog-Rain,87
2014-2-3,14,11,8,10,9,8,94,88,67,1013,1010,1008,10,9,6,16,5,,0.51,5,Rain,109
2014-2-4,14,12,9,10,9,8,94,89,75,1015,1014,1012,19,10,10,19,6,,0.25,4,Rain,132
2014-2-5,12,9,7,9,8,7,94,87,68,1015,1011,1003,14,10,6,29,14,48,1.02,6,Rain-Thunderstorm,111
2014-2-6,14,10,6,9,7,5,100,85,61,1017,1012,1002,31,11,5,35,18,58,0.00,3,Rain,128
2014-2-7,14,9,4,12,8,3,94,86,68,1017,1013,1009,19,10,6,29,13,,1.02,4,Rain,144
2014-2-8,14,12,10,10,8,6,94,78,55,1013,1009,1004,14,10,10,29,16,,1.02,4,Rain,226
2014-2-9,13,11,8,10,8,6,94,79,53,1009,1004,1000,19,10,10,40,19,45,0.51,4,Rain,235
2014-2-10,14,11,7,12,9,6,100,92,82,1010,1002,997,10,7,2,37,18,50,28.96,6,Rain,116
2014-2-11,14,12,9,10,9,8,95,88,66,1006,1004,1002,19,10,7,23,10,,7.11,5,Fog-Rain,103
2014-2-12,14,9,4,11,7,4,94,86,57,1014,1008,1005,19,7,0,23,6,,0.00,3,Fog-Rain,231
2014-2-13,14,9,4,10,7,4,93,83,45,1015,1011,1006,14,10,8,35,10,,0.00,4,,154
2014-2-14,15,12,9,9,8,6,94,78,56,1015,1011,1006,19,11,10,50,23,63,0.00,2,,259
2014-2-15,18,12,7,13,9,7,94,84,56,1016,1015,1014,19,10,10,19,8,,0.00,5,,138
2014-2-16,17,15,13,14,12,11,95,88,69,1016,1015,1013,14,10,10,23,8,,0.00,5,,141
2014-2-17,15,12,8,13,11,7,95,86,68,1020,1015,1012,19,10,10,27,13,,0.00,4,Rain,244
2014-2-18,18,13,8,10,8,6,100,76,44,1020,1017,1013,14,10,10,23,10,,0.00,3,,110
2014-2-19,16,13,12,14,11,8,95,84,62,1013,1011,1010,14,9,3,23,13,,2.03,6,Rain-Thunderstorm,144
2014-2-20,14,12,10,11,9,8,94,86,62,1014,1012,1010,14,9,5,19,8,,0.51,6,Fog-Rain,98
2014-2-21,15,11,7,11,9,7,94,88,65,1014,1012,1011,19,10,4,16,8,,1.02,5,Rain,144
2014-2-22,15,11,8,10,8,7,94,80,59,1018,1013,1010,18,10,2,29,14,,0.76,3,Rain-Thunderstorm,234
2014-2-23,15,10,5,7,4,2,100,75,34,1023,1021,1018,31,12,10,19,10,,0.00,2,,121
2014-2-24,15,8,2,7,4,1,100,77,32,1023,1021,1020,26,15,10,16,6,,0.00,,Fog,118
2014-2-25,14,8,2,9,6,2,100,84,56,1022,1020,1020,19,11,10,16,10,,0.00,2,,140
2014-2-26,12,9,7,11,8,7,95,91,85,1022,1020,1019,11,10,3,29,14,,11.94,4,Fog-Rain-Thunderstorm,113
2014-2-27,13,10,6,9,7,5,100,85,54,1022,1020,1018,19,9,5,19,10,,0.51,4,Rain-Thunderstorm,122
2014-2-28,15,11,6,8,6,5,93,86,61,1018,1010,1002,10,8,3,32,14,,6.10,6,Rain-Thunderstorm,111
2014-3-1,10,8,7,7,6,5,93,88,73,1002,996,992,10,8,1,29,23,,22.10,6,Rain,101
2014-3-2,13,9,4,8,6,3,94,80,51,1002,997,993,19,10,10,21,13,,0.00,3,,89
2014-3-3,11,7,3,8,6,2,100,88,66,1001,996,992,14,10,8,23,11,,0.51,6,Rain,111
2014-3-4,13,10,7,8,6,3,96,77,47,1001,993,989,14,10,10,27,14,,0.51,5,Rain,54
2014-3-5,16,11,7,8,6,3,93,73,41,1014,1008,1001,26,11,10,16,6,,0.00,4,,94
2014-3-6,16,11,5,7,3,1,96,59,25,1021,1017,1014,31,11,10,27,10,,0.00,3,,52
2014-3-7,17,11,4,9,6,3,100,72,35,1023,1021,1020,31,12,10,19,8,,0.00,2,,292
2014-3-8,17,11,5,8,3,-1,100,62,21,1028,1024,1022,26,12,10,35,11,,0.00,3,,88
2014-3-9,18,13,8,5,3,2,76,51,23,1029,1026,1024,31,21,10,35,13,,0.00,,,89
2014-3-10,16,10,5,6,4,3,93,62,36,1024,1021,1018,19,11,10,35,13,53,0.00,2,,98
2014-3-11,16,11,7,9,5,1,81,63,40,1027,1022,1020,14,13,10,32,16,,0.00,,,113
2014-3-12,18,10,2,6,3,1,93,62,26,1030,1028,1027,19,14,10,19,10,,0.00,,,155
2014-3-13,20,11,2,10,5,2,100,77,27,1029,1027,1025,19,14,10,16,6,,0.00,,,127
2014-3-14,19,12,4,10,7,4,100,81,35,1026,1024,1022,14,9,1,16,6,,0.00,1,Fog,160
2014-3-15,16,10,4,12,8,4,100,88,67,1023,1019,1015,14,8,1,21,8,,0.00,2,Fog,167
2014-3-16,16,10,5,12,8,-30,100,87,4,1019,1016,1014,8,5,0,23,6,,0.00,3,Fog,237
2014-3-17,18,13,8,13,11,8,100,88,65,1023,1021,1018,19,6,2,16,6,,0.00,2,Fog,243
2014-3-18,18,13,8,13,11,7,100,87,65,1023,1021,1020,14,6,0,16,6,,0.00,3,Fog,170
2014-3-19,17,12,8,12,11,8,100,87,66,1023,1021,1020,14,9,1,13,6,,0.00,4,Fog,156
2014-3-20,21,13,5,12,9,6,100,84,46,1025,1023,1022,19,4,0,16,8,,0.00,2,Fog,119
2014-3-21,17,13,8,12,10,8,100,86,62,1023,1021,1020,10,7,0,16,5,,0.25,4,Fog,206
2014-3-22,16,13,12,13,12,11,100,90,69,1020,1015,1008,19,9,2,16,8,,0.51,6,Rain,181
2014-3-23,14,11,7,13,8,4,94,79,49,1009,1003,1000,19,10,5,48,23,66,1.02,5,Rain-Thunderstorm,228
2014-3-24,14,10,6,8,6,2,100,78,47,1011,1006,1001,26,11,10,42,16,,2.03,4,Rain-Thunderstorm,161
2014-3-25,13,9,4,9,6,4,96,88,58,1011,1008,1005,26,10,8,26,11,,0.51,4,Rain,110
2014-3-26,13,10,7,7,6,4,96,76,51,1008,1007,1005,19,10,10,23,10,,0.51,5,Rain,70
2014-3-27,15,12,8,8,5,3,93,63,38,1008,1005,1003,19,11,10,39,19,60,0.00,6,,54
2014-3-28,18,12,6,11,7,4,100,78,32,1020,1014,1008,26,12,10,19,8,,0.00,2,,290
2014-3-29,22,13,5,11,7,5,100,76,26,1022,1020,1019,19,12,10,24,10,,0.00,1,,125
2014-3-30,19,13,6,10,8,6,100,75,38,1021,1019,1017,19,12,8,16,8,,0.00,,,152
2014-3-31,17,11,5,11,8,5,94,83,45,1019,1017,1016,19,15,10,19,8,,0.00,,,203
2014-4-1,17,11,5,11,8,4,100,89,68,1018,1017,1017,19,7,0,23,6,,0.00,4,Fog,230
2014-4-2,18,12,6,11,8,6,100,87,68,1018,1016,1014,19,10,6,19,6,,0.00,2,Fog,129
2014-4-3,20,14,9,11,8,6,94,70,43,1015,1010,1006,19,11,10,26,11,,0.00,2,,107
2014-4-4,16,13,11,12,11,9,94,87,73,1006,1003,1000,19,10,3,24,14,,7.87,4,Rain-Thunderstorm,115
2014-4-5,17,14,11,13,11,9,100,87,60,1013,1008,1005,14,10,5,19,5,,0.00,6,Rain,96
2014-4-6,21,14,8,13,11,8,100,82,52,1018,1015,1013,26,11,10,16,5,,0.00,3,,265
2014-4-7,22,15,8,14,11,7,100,80,50,1021,1019,1018,26,19,10,21,8,,0.00,,,245
2014-4-8,18,13,9,15,12,9,100,91,68,1021,1020,1017,19,8,0,19,6,,0.51,4,Fog-Rain,221
2014-4-9,19,16,11,14,13,10,95,87,67,1019,1017,1016,19,10,8,14,6,,0.00,4,,227
2014-4-10,19,13,7,13,9,6,100,81,35,1020,1018,1017,19,9,4,19,8,,0.00,3,Fog,181
2014-4-11,18,14,11,13,11,9,94,84,56,1018,1017,1016,26,10,6,23,8,,0.00,5,,253
2014-4-12,20,14,8,13,11,7,100,85,60,1017,1016,1015,14,10,10,16,6,,0.00,2,,193
2014-4-13,18,14,11,14,12,10,100,89,67,1017,1016,1015,11,10,6,16,6,,0.25,4,Rain,263
2014-4-14,19,13,8,15,12,7,100,89,72,1018,1016,1013,19,7,0,23,10,,0.00,3,Fog,209
2014-4-15,19,13,8,14,9,1,100,74,28,1015,1012,1010,14,9,2,29,8,,1.02,3,Fog-Hail-Thunderstorm,102
2014-4-16,17,12,6,7,2,-2,81,52,19,1021,1018,1015,31,12,10,27,14,,0.00,2,,69
2014-4-17,17,10,2,10,5,0,94,70,22,1021,1017,1014,31,14,10,23,8,,0.00,1,,210
2014-4-18,17,11,5,12,9,5,100,86,63,1015,1010,1004,26,13,10,23,11,,0.00,3,,246
2014-4-19,16,13,11,12,11,9,95,89,69,1006,1002,1000,19,10,5,39,19,50,6.10,6,Fog-Rain-Thunderstorm,96
2014-4-20,18,11,5,12,9,5,100,83,53,1007,1006,1005,19,9,0,19,8,,0.00,3,Fog,125
2014-4-21,17,14,11,14,11,10,100,87,63,1009,1006,1004,19,10,0,14,6,,1.02,5,Fog-Rain-Thunderstorm,90
2014-4-22,20,14,9,14,12,9,100,89,61,1015,1012,1009,19,7,0,16,6,,0.00,3,Fog,166
2014-4-23,22,16,10,15,12,9,100,84,55,1016,1015,1014,14,6,0,23,6,,0.00,4,Fog,242
2014-4-24,19,15,11,16,14,10,100,89,75,1016,1015,1014,14,9,3,21,8,,0.00,4,Fog,266
2014-4-25,21,16,11,16,13,11,94,87,64,1015,1011,1008,19,9,5,16,6,,0.00,3,,270
2014-4-26,20,16,11,16,13,11,100,87,72,1011,1009,1009,14,9,1,23,8,,0.00,2,Fog,268
2014-4-27,15,12,10,13,12,9,94,91,80,1010,1006,1003,19,10,3,14,6,,7.11,5,Rain,270
2014-4-28,16,13,12,14,12,11,100,91,81,1006,1005,1004,14,10,10,19,6,,0.51,6,Rain-Thunderstorm,203
2014-4-29,18,13,9,13,11,9,100,83,59,1011,1008,1005,14,10,6,14,8,,0.00,4,Fog-Rain-Thunderstorm,236
2014-4-30,17,13,9,13,11,9,94,86,68,1011,1009,1006,19,11,10,35,8,,3.05,3,Rain,158
2014-5-1,19,12,6,13,10,6,95,80,48,1011,1010,1008,19,10,8,21,8,,0.00,3,Fog,288
2014-5-2,16,13,11,14,11,10,94,91,77,1010,1008,1007,19,9,3,21,8,,11.94,5,Rain-Thunderstorm,148
2014-5-3,19,15,11,13,11,9,94,83,48,1007,1006,1005,26,10,6,27,6,,0.25,5,Rain,358
2014-5-4,21,16,11,14,11,9,94,77,54,1014,1010,1007,31,11,10,19,8,,0.00,3,,108
2014-5-5,20,13,7,12,9,6,100,73,32,1019,1017,1014,31,14,10,16,8,,0.00,1,,169
2014-5-6,21,14,8,14,11,8,100,84,48,1022,1020,1018,26,12,10,21,6,,0.00,2,,209
2014-5-7,21,15,9,15,12,9,100,85,57,1021,1019,1017,19,11,10,21,8,,0.00,3,,172
2014-5-8,23,17,11,14,13,10,94,77,43,1020,1018,1017,26,12,10,24,8,,0.00,3,,149
2014-5-9,21,16,10,15,13,9,94,82,55,1019,1017,1017,19,11,10,19,6,,0.00,2,Fog,252
2014-5-10,21,16,10,15,13,9,100,82,55,1017,1016,1015,19,10,2,16,6,,0.00,3,Fog,221
2014-5-11,22,18,13,16,14,12,94,81,62,1016,1012,1009,14,10,8,29,11,,0.00,3,,199
2014-5-12,19,16,12,15,13,11,100,82,57,1014,1012,1010,14,10,10,24,11,,0.00,2,,237
2014-5-13,20,16,11,12,10,7,94,72,51,1013,1012,1010,19,11,10,27,16,,0.00,3,,225
2014-5-14,22,15,8,11,7,1,94,63,24,1018,1016,1013,31,13,10,32,11,,0.00,2,,246
2014-5-15,21,14,7,11,6,-3,100,60,13,1019,1017,1016,31,12,10,24,10,,0.00,2,,224
2014-5-16,22,16,10,13,9,1,100,71,22,1016,1014,1012,31,13,10,24,8,,0.00,2,,210
2014-5-17,22,17,12,13,11,6,96,74,39,1017,1015,1014,26,11,10,21,8,,0.00,3,,214
2014-5-18,22,15,8,11,9,8,100,69,39,1018,1016,1015,19,12,10,29,10,37,0.00,1,,149
2014-5-19,20,16,11,13,9,5,88,68,33,1018,1016,1015,19,11,10,26,11,,0.00,5,,123
2014-5-20,24,19,13,14,11,5,94,68,21,1020,1018,1017,26,12,10,23,8,,0.00,4,,203
2014-5-21,26,18,11,16,13,10,100,73,40,1020,1018,1016,19,12,10,21,8,,0.00,2,,139
2014-5-22,27,20,13,16,14,12,95,74,43,1018,1016,1014,19,11,10,27,10,,0.00,2,Rain,138
2014-5-23,23,18,14,16,14,10,94,77,38,1016,1015,1013,19,10,8,23,10,,0.00,4,Rain,240
2014-5-24,23,17,11,15,12,6,94,75,32,1018,1017,1016,26,12,10,21,8,,0.00,1,,255
2014-5-25,27,18,10,14,9,4,94,64,18,1018,1016,1014,19,12,10,26,8,,0.00,2,,177
2014-5-26,22,18,14,15,13,11,94,74,41,1016,1015,1014,31,11,10,27,13,,0.00,3,,252
2014-5-27,21,18,15,14,13,11,88,75,55,1015,1014,1013,19,11,10,37,21,,0.00,4,Rain,253
2014-5-28,22,18,15,14,13,11,88,72,45,1014,1012,1011,19,11,10,27,21,,0.00,3,,261
2014-5-29,21,16,10,14,12,9,100,80,57,1013,1012,1012,26,11,10,24,10,,0.00,2,,204
2014-5-30,22,16,10,15,13,11,95,80,54,1014,1013,1013,19,11,10,21,8,,0.00,2,,218
2014-5-31,23,19,14,15,13,8,94,78,34,1017,1014,1013,26,11,10,19,8,,1.02,4,Rain,132
2014-6-1,23,17,10,13,9,5,94,62,27,1017,1016,1015,31,12,10,23,8,,0.00,2,,246
2014-6-2,25,18,10,16,10,6,94,66,26,1017,1015,1013,31,14,10,23,10,,0.00,1,,247
2014-6-3,26,19,12,16,13,7,100,73,32,1014,1013,1012,31,14,10,21,8,,0.00,2,,234
2014-6-4,23,18,12,16,14,12,100,80,56,1014,1012,1012,19,11,10,23,8,,0.00,2,,242
2014-6-5,25,19,14,17,14,11,94,70,34,1018,1015,1013,19,11,10,23,8,,0.00,2,,266
2014-6-6,26,19,13,17,14,11,94,72,44,1020,1018,1017,31,15,10,16,6,,0.00,2,,222
2014-6-7,28,21,13,18,14,9,95,70,27,1019,1018,1017,31,18,10,21,6,,9.91,,,226
2014-6-8,31,22,14,18,15,12,94,66,30,1020,1019,1018,26,15,10,24,8,,0.00,2,,296
2014-6-9,34,26,17,18,16,9,94,61,14,1019,1017,1016,31,18,10,23,10,,0.00,,,137
2014-6-10,32,23,15,22,18,14,100,70,30,1019,1017,1017,31,17,10,21,8,,0.00,1,,210
2014-6-11,31,23,16,23,18,16,100,76,35,1020,1018,1017,26,12,10,21,8,,0.00,2,,250
2014-6-12,32,24,18,23,21,17,100,82,49,1020,1018,1016,26,11,5,23,8,,0.00,3,Thunderstorm,257
2014-6-13,31,26,20,24,21,19,100,79,47,1017,1014,1011,14,10,8,21,8,,0.00,2,,264
2014-6-14,31,26,20,21,19,15,100,73,35,1011,1008,1005,19,10,8,23,10,29,7.87,3,Rain-Thunderstorm,118
2014-6-15,23,21,18,20,16,12,100,73,48,1012,1010,1008,19,10,6,29,14,,0.51,6,Rain-Thunderstorm,58
2014-6-16,23,20,16,16,14,12,94,67,50,1012,1011,1010,31,11,10,24,18,,0.00,5,Rain,72
2014-6-17,26,20,13,16,13,10,95,65,32,1013,1012,1010,26,11,10,23,10,,0.00,3,,84
2014-6-18,26,20,13,16,14,11,88,62,39,1014,1013,1012,31,12,10,23,10,,0.00,2,,41
2014-6-19,26,20,14,18,16,14,100,72,44,1015,1014,1013,26,12,10,24,10,,0.00,1,,255
2014-6-20,25,21,16,19,18,16,97,80,53,1015,1014,1012,14,10,10,26,10,,0.00,2,,272
2014-6-21,27,21,15,20,17,14,100,75,35,1017,1015,1013,26,13,10,19,8,,0.00,2,,235
2014-6-22,28,22,16,22,18,15,100,80,45,1021,1018,1016,31,12,10,23,8,,0.00,2,,202
2014-6-23,29,23,17,20,18,13,100,72,41,1021,1019,1016,31,12,10,26,8,,0.00,2,,149
2014-6-24,29,22,16,22,18,14,100,73,31,1017,1012,1009,26,14,10,32,11,,0.00,1,,163
2014-6-25,26,23,21,22,21,17,100,85,57,1011,1008,1006,19,10,5,35,11,,3.05,4,Rain-Thunderstorm,265
2014-6-26,24,21,18,21,18,15,94,84,52,1013,1011,1010,19,11,5,21,10,,7.11,3,Rain-Thunderstorm,291
2014-6-27,27,21,16,22,18,15,100,83,56,1018,1015,1012,31,12,10,24,8,,0.00,2,,194
2014-6-28,27,22,17,20,17,14,100,73,42,1019,1017,1015,31,11,7,16,8,,0.00,2,,238
2014-6-29,28,22,16,21,18,14,94,77,33,1016,1011,1006,26,11,8,27,11,,1.02,3,Rain-Thunderstorm,156
2014-6-30,27,22,17,20,18,17,94,78,53,1015,1010,1006,19,11,10,29,13,,0.00,2,,258
2014-7-1,26,21,16,20,18,16,94,77,48,1018,1016,1014,26,11,10,19,10,,0.00,2,,288
2014-7-2,27,21,16,20,18,15,94,76,49,1022,1019,1017,31,13,10,16,8,,0.00,2,,230
2014-7-3,32,24,16,22,18,15,100,75,38,1024,1022,1021,31,15,10,23,8,,0.00,1,,113
2014-7-4,32,26,20,21,18,16,94,69,35,1021,1017,1013,26,11,10,35,11,,0.00,4,Rain,154
2014-7-5,26,23,20,21,20,19,94,82,66,1015,1013,1012,14,10,10,23,11,,0.00,3,,242
2014-7-6,28,23,18,21,19,17,95,80,53,1016,1015,1014,26,12,10,19,8,,0.00,3,,229
2014-7-7,29,23,18,21,18,16,94,75,41,1016,1015,1013,31,12,6,37,8,,0.25,5,Rain-Thunderstorm,151
2014-7-8,24,21,18,20,18,15,94,81,55,1014,1010,1007,19,11,6,47,21,64,7.87,4,Rain,215
2014-7-9,24,19,15,19,16,15,100,76,55,1008,1007,1006,19,11,10,42,19,55,0.51,3,Rain-Thunderstorm,222
2014-7-10,23,19,14,17,15,13,100,78,54,1008,1006,1005,31,12,10,29,13,,0.00,3,Rain-Thunderstorm,194
2014-7-11,25,19,14,18,17,14,100,82,58,1010,1008,1008,26,12,10,23,10,,0.00,2,,216
2014-7-12,27,21,15,19,17,14,94,81,47,1012,1011,1010,26,11,10,26,8,,2.03,5,Rain-Thunderstorm,126
2014-7-13,25,21,17,20,18,17,100,84,61,1013,1012,1011,26,11,10,24,8,,0.00,4,Rain-Thunderstorm,194
2014-7-14,23,21,18,19,18,17,94,87,72,1015,1013,1012,19,10,6,23,10,,14.99,5,Rain-Thunderstorm,266
2014-7-15,28,22,15,21,18,15,100,80,52,1017,1016,1015,31,11,3,19,6,,0.00,1,Fog,294
2014-7-16,30,23,16,21,18,16,94,72,41,1018,1017,1016,26,14,10,26,8,,0.00,1,,294
2014-7-17,32,24,18,22,19,17,100,74,36,1019,1017,1017,31,15,10,21,8,,0.00,2,,262
2014-7-18,30,25,20,23,21,18,100,82,47,1019,1017,1016,26,9,0,19,8,,0.00,3,Fog,238
2014-7-19,33,26,18,23,19,16,94,73,27,1017,1016,1015,19,14,10,19,6,,0.00,2,,197
2014-7-20,32,25,18,21,18,15,94,67,34,1016,1014,1011,31,12,10,32,10,,0.00,3,Rain,123
2014-7-21,24,21,18,21,19,17,100,85,68,1012,1009,1008,14,9,1,27,11,,14.99,5,Rain-Thunderstorm,213
2014-7-22,27,22,17,21,18,15,100,77,41,1009,1008,1007,31,11,2,24,11,,0.00,4,Rain-Thunderstorm,307
2014-7-23,28,23,19,22,21,19,100,86,65,1011,1009,1009,26,11,10,21,8,,0.00,4,Rain,263
2014-7-24,26,22,19,21,20,19,95,87,65,1012,1010,1009,26,11,8,19,6,,6.10,4,Rain-Thunderstorm,145
2014-7-25,27,23,18,22,20,18,100,84,63,1014,1012,1012,19,10,3,19,6,,0.00,3,Fog-Rain,173
2014-7-26,27,23,20,24,21,19,96,87,60,1013,1010,1009,19,10,1,24,8,,10.92,4,Rain-Thunderstorm,142
2014-7-27,27,22,18,22,20,18,100,85,56,1012,1010,1009,19,10,5,21,8,,14.99,3,Rain-Thunderstorm,174
2014-7-28,28,23,18,23,21,18,100,83,53,1013,1011,1010,26,11,8,23,8,,0.00,3,Fog,214
2014-7-29,24,21,19,22,19,16,100,86,69,1010,1008,1006,19,10,2,24,13,,24.89,6,Rain-Thunderstorm,277
2014-7-30,24,20,17,19,18,16,95,86,67,1009,1006,1003,19,9,3,19,8,,0.25,4,Rain,288
2014-7-31,26,21,17,21,19,16,95,84,64,1012,1010,1008,19,11,10,19,8,,0.00,3,,239
2014-8-1,27,22,18,22,20,18,100,84,65,1012,1011,1010,19,10,3,16,6,,0.00,2,Fog,255
2014-8-2,29,23,18,21,19,17,94,76,48,1012,1011,1011,31,11,5,14,6,,0.00,1,Fog,200
2014-8-3,27,23,20,22,21,19,94,85,63,1014,1013,1011,19,11,8,21,11,,0.51,4,Rain-Thunderstorm,196
2014-8-4,27,23,19,23,21,18,100,86,62,1016,1015,1014,19,10,0,21,8,,0.00,2,Fog,222
2014-8-5,27,23,19,23,20,16,100,86,67,1015,1014,1012,19,10,6,23,8,,0.00,3,Thunderstorm,155
2014-8-6,29,22,16,22,19,16,100,81,57,1015,1014,1013,31,14,10,23,6,,0.00,1,,282
2014-8-7,29,23,18,22,19,17,94,80,48,1014,1013,1012,31,14,10,19,8,,0.00,1,,215
2014-8-8,29,23,18,22,19,17,95,79,48,1015,1014,1013,19,10,2,16,6,,0.00,1,,193
2014-8-9,28,23,18,23,20,18,100,82,58,1016,1015,1015,19,11,10,14,8,,0.00,2,,192
2014-8-10,31,24,18,23,20,18,100,76,49,1017,1015,1014,31,23,10,16,8,,0.00,,,153
2014-8-11,29,24,19,24,21,19,94,83,60,1015,1014,1012,31,12,10,21,8,,0.00,2,,154
2014-8-12,29,26,22,24,22,21,95,86,66,1014,1012,1010,19,10,8,21,10,,0.00,3,,169
2014-8-13,29,26,22,24,22,20,94,85,67,1012,1009,1007,19,10,10,35,11,,0.00,3,Rain,190
2014-8-14,25,22,20,20,17,16,88,70,52,1012,1010,1008,19,11,10,37,19,,0.00,3,,244
2014-8-15,24,20,16,20,18,16,94,79,57,1015,1013,1012,19,10,10,35,16,48,1.02,3,Rain,231
2014-8-16,25,20,15,19,17,15,94,75,50,1017,1015,1014,26,11,10,21,10,,0.00,2,,135
2014-8-17,27,19,12,16,14,10,100,71,30,1019,1017,1015,31,18,10,21,8,,0.00,1,,111
2014-8-18,25,18,12,19,16,12,100,78,56,1016,1015,1014,31,12,10,16,6,,0.00,2,,203
2014-8-19,28,22,17,22,19,17,94,81,52,1014,1013,1012,26,11,10,26,11,,0.00,3,,145
2014-8-20,28,23,18,22,20,18,100,85,61,1014,1013,1012,19,11,10,21,8,,0.00,3,,200
2014-8-21,26,21,16,19,18,15,100,78,49,1016,1014,1013,26,12,10,23,10,,0.00,1,,227
2014-8-22,26,20,14,19,17,13,94,79,52,1016,1015,1015,26,12,10,19,8,,0.00,2,,172
2014-8-23,24,21,18,20,19,18,100,88,68,1016,1014,1013,14,10,10,23,8,,2.03,5,Rain,136
2014-8-24,26,21,17,20,18,16,94,80,62,1016,1015,1013,19,11,10,35,11,,0.00,3,,257
2014-8-25,26,21,16,20,17,15,95,82,55,1019,1017,1016,19,11,10,19,8,,0.00,2,,185
2014-8-26,27,21,16,22,18,16,100,82,47,1017,1014,1012,26,11,10,23,10,,0.00,3,Rain,156
2014-8-27,27,23,20,22,21,19,95,86,68,1013,1011,1010,19,11,10,34,13,,0.00,3,,199
2014-8-28,29,22,16,20,18,16,100,78,43,1016,1014,1012,19,11,8,23,10,,0.00,1,,135
2014-8-29,30,24,18,21,18,16,94,75,46,1017,1016,1015,19,13,10,24,10,,0.00,1,,294
2014-8-30,27,22,17,22,19,16,94,82,48,1017,1015,1014,19,11,10,16,6,,0.00,1,,229
2014-8-31,27,22,17,21,19,17,100,84,56,1015,1012,1008,19,10,3,16,6,,0.00,2,,212
2014-9-1,26,21,16,21,14,9,100,69,28,1009,1006,1004,19,11,10,29,11,48,0.00,3,Rain-Thunderstorm,60
2014-9-2,28,20,12,15,12,9,95,65,23,1011,1009,1008,26,12,10,24,8,,0.00,1,,124
2014-9-3,25,20,15,18,16,13,88,74,50,1012,1011,1011,19,11,10,21,11,,0.00,2,,110
2014-9-4,26,20,14,20,17,14,100,78,45,1014,1012,1012,19,11,10,13,6,,0.00,2,,55
2014-9-5,27,21,16,23,19,16,100,84,56,1014,1012,1011,19,10,10,19,5,,9.91,4,Rain-Thunderstorm,120
2014-9-6,27,22,17,20,19,16,95,79,57,1012,1011,1010,19,11,10,16,8,,0.00,2,,273
2014-9-7,27,21,16,21,19,16,100,85,56,1015,1013,1012,19,10,6,19,6,,0.00,2,Fog,185
2014-9-8,27,22,17,21,19,16,100,85,58,1017,1016,1014,19,11,8,16,8,,0.00,2,,172
2014-9-9,27,22,17,22,19,16,94,86,64,1017,1016,1014,14,8,3,16,6,,0.00,2,,200
2014-9-10,23,21,18,21,19,17,100,93,83,1015,1012,1010,19,10,3,23,8,,7.87,6,Rain-Thunderstorm,110
2014-9-11,25,21,18,20,18,16,94,82,48,1011,1009,1007,19,10,3,26,8,,0.76,4,Rain-Thunderstorm,121
2014-9-12,23,19,16,17,16,13,100,79,52,1013,1010,1008,31,12,10,34,10,,0.00,3,Rain-Thunderstorm,103
2014-9-13,24,19,13,18,16,13,94,80,56,1016,1014,1013,19,11,10,16,8,,0.00,1,,151
2014-9-14,25,19,13,18,16,12,100,81,44,1016,1015,1014,26,14,10,19,6,,0.00,1,,122
2014-9-15,25,19,14,20,17,14,100,86,59,1016,1015,1015,26,11,10,13,6,,0.00,3,,120
2014-9-16,27,21,16,18,17,14,100,79,38,1015,1015,1014,19,11,10,19,8,,0.00,2,,129
2014-9-17,27,21,15,19,16,13,100,75,38,1015,1014,1013,26,12,10,23,10,,0.00,2,,111
2014-9-18,27,22,17,21,18,15,94,77,46,1016,1015,1014,19,11,10,23,10,,0.00,3,,114
2014-9-19,25,22,19,22,19,18,100,86,62,1018,1016,1015,19,10,2,23,10,39,10.92,4,Rain-Thunderstorm,112
2014-9-20,28,24,20,22,21,19,95,85,62,1017,1016,1015,26,11,6,23,8,,0.00,3,Rain,222
2014-9-21,26,22,18,22,19,17,100,87,62,1017,1015,1013,14,7,0,16,8,,0.00,3,Fog,169
2014-9-22,26,22,18,22,20,17,94,86,70,1013,1010,1008,19,10,10,26,14,,0.00,3,,219
2014-9-23,24,20,15,17,11,4,100,62,20,1016,1013,1009,26,14,10,29,14,,0.00,2,,101
2014-9-24,23,16,9,15,11,5,94,68,24,1017,1015,1014,19,11,10,19,10,,0.00,4,,122
2014-9-25,24,19,15,18,16,14,94,81,49,1018,1015,1013,19,11,10,23,10,,0.00,4,Rain,120
2014-9-26,25,19,13,15,13,10,100,72,38,1022,1020,1018,26,16,10,19,8,,0.00,,,95
2014-9-27,27,19,11,19,14,11,100,80,35,1026,1024,1021,31,20,10,14,6,,0.00,,,121
2014-9-28,28,20,13,18,14,11,100,73,29,1028,1026,1025,19,14,10,23,10,,0.00,,,117
2014-9-29,26,19,12,20,16,12,97,77,31,1028,1027,1026,26,12,10,21,8,,0.00,1,,151
2014-9-30,25,19,13,19,17,13,94,83,44,1028,1026,1025,26,11,10,19,8,,0.00,3,Rain,128
2014-10-1,23,20,18,20,18,17,100,92,83,1025,1023,1021,14,9,2,23,10,,13.97,5,Rain-Thunderstorm,111
2014-10-2,26,21,16,19,16,12,100,74,33,1025,1022,1021,31,12,5,27,10,,0.00,2,Fog-Rain-Thunderstorm,100
2014-10-3,26,20,14,17,14,12,88,71,34,1023,1021,1019,31,16,10,26,10,,0.00,1,,106
2014-10-4,25,18,11,16,13,9,100,75,27,1020,1017,1015,31,14,10,23,8,,0.00,1,,108
2014-10-5,24,17,10,17,13,10,100,79,39,1016,1015,1014,31,15,10,19,8,,0.00,1,,68
2014-10-6,24,18,13,15,13,12,100,79,43,1015,1014,1013,19,12,10,16,8,,0.00,2,,107
2014-10-7,24,18,11,17,14,11,100,83,51,1018,1016,1015,14,10,8,19,8,,0.00,4,,119
2014-10-8,26,21,17,19,18,16,94,82,58,1019,1017,1017,19,10,10,26,11,,0.00,3,,123
2014-10-9,25,22,18,20,18,17,94,81,65,1018,1016,1016,19,10,10,24,13,,0.00,3,,114
2014-10-10,27,23,20,20,19,17,94,81,61,1018,1017,1016,26,11,10,21,13,,0.00,4,,116
2014-10-11,26,21,17,22,19,16,100,86,68,1017,1016,1014,19,10,3,24,13,,7.11,4,Rain-Thunderstorm,137
2014-10-12,26,21,15,21,18,14,100,88,67,1017,1015,1014,14,10,10,23,13,,0.25,3,Rain-Thunderstorm,114
2014-10-13,26,22,18,21,19,17,95,90,75,1015,1012,1009,14,10,2,32,14,,10.92,6,Rain-Thunderstorm,137
2014-10-14,25,20,16,19,17,15,100,87,63,1013,1010,1008,19,10,6,21,10,,0.00,4,Rain-Thunderstorm,106
2014-10-15,24,20,17,19,17,16,100,89,69,1011,1008,1007,19,10,6,16,6,,0.25,4,Rain-Thunderstorm,137
2014-10-16,23,21,18,19,18,16,95,89,73,1016,1014,1010,19,10,8,19,8,,1.02,5,Rain,235
2014-10-17,25,21,17,21,19,17,95,89,78,1020,1016,1015,14,10,10,34,10,,0.00,5,Rain,239
2014-10-18,24,19,15,20,17,15,100,89,69,1025,1022,1019,19,8,0,13,6,,0.00,2,Fog,133
2014-10-19,24,19,14,19,17,13,100,89,65,1025,1024,1023,19,5,0,14,5,,0.00,3,Fog,138
2014-10-20,23,19,14,19,16,14,100,91,72,1024,1022,1018,19,7,0,16,6,,0.00,3,Fog,136
2014-10-21,23,21,18,19,18,17,100,89,70,1018,1012,1005,19,10,10,23,8,,0.76,4,Rain,139
2014-10-22,19,14,9,19,4,-7,94,46,9,1013,1007,1001,31,13,10,40,21,53,0.00,1,,311
2014-10-23,22,14,6,10,6,1,93,59,20,1012,1009,1007,31,16,10,23,8,,0.00,3,,65
2014-10-24,21,14,8,11,8,5,100,70,27,1016,1012,1010,26,12,10,21,8,,0.00,3,,139
2014-10-25,21,14,7,10,9,7,95,75,36,1021,1018,1015,31,20,10,21,10,,0.00,,,-1
2014-10-26,19,14,9,10,8,6,94,72,38,1023,1022,1021,19,15,10,23,6,,0.00,3,,-1
2014-10-27,18,14,9,9,7,6,87,66,41,1025,1023,1022,31,19,10,24,16,,0.00,1,,-1
2014-10-28,18,12,6,8,7,5,93,71,37,1024,1021,1019,19,14,10,26,14,,0.00,1,,110
2014-10-29,18,12,6,10,7,5,100,78,39,1021,1019,1018,19,13,10,23,10,,0.00,1,,108
2014-10-30,20,13,6,11,8,5,100,80,44,1025,1022,1020,31,14,10,13,6,,0.00,2,,115
2014-10-31,20,12,5,11,7,4,100,79,28,1026,1025,1024,26,16,10,13,8,,0.00,,,109
2014-11-1,21,13,5,13,8,5,100,81,36,1025,1024,1023,31,14,8,13,6,,0.00,,,101
2014-11-2,20,13,6,15,9,5,100,86,60,1024,1022,1020,19,9,2,14,8,,0.00,2,Fog,130
2014-11-3,20,14,8,13,11,7,100,84,56,1022,1019,1015,19,8,2,21,10,,0.00,2,Fog,116
2014-11-4,22,17,13,17,14,11,94,80,61,1015,1007,1002,19,10,10,34,21,52,1.02,4,Rain,132
2014-11-5,20,17,14,18,16,13,100,87,71,1005,1001,999,11,9,3,35,21,58,2.03,6,Rain-Thunderstorm,175
2014-11-6,16,14,13,14,13,12,100,93,86,1009,1007,1005,14,8,3,24,11,,14.99,6,Rain,81
2014-11-7,19,16,13,14,13,12,94,89,70,1010,1008,1007,19,10,6,11,3,,0.00,4,Fog,267
2014-11-8,20,15,10,14,12,9,95,86,62,1012,1011,1009,19,9,0,11,5,,0.00,2,Fog,137
2014-11-9,20,14,9,15,12,8,100,87,64,1014,1013,1012,19,7,0,23,8,,0.00,2,Fog,119
2014-11-10,17,15,13,15,14,12,94,89,73,1015,1014,1014,11,8,2,29,18,,35.05,6,Rain-Thunderstorm,96
2014-11-11,18,16,13,15,13,13,96,89,68,1016,1012,1007,10,9,5,24,11,,3.05,6,Rain-Thunderstorm,100
2014-11-12,16,14,13,14,13,12,94,92,83,1008,1004,1003,11,10,10,23,11,,0.76,6,Rain,117
2014-11-13,18,14,11,14,12,11,94,89,66,1013,1008,1003,19,10,3,14,6,,0.00,4,Rain,216
2014-11-14,20,17,13,14,13,12,95,88,61,1015,1014,1013,19,9,3,13,6,,0.00,4,Rain,112
2014-11-15,17,15,13,15,13,11,95,86,72,1013,1007,1001,10,10,6,34,18,,7.87,5,Rain,131
2014-11-16,18,14,11,12,11,9,94,77,55,1007,1006,1004,19,10,8,37,21,50,3.05,4,Rain-Thunderstorm,200
2014-11-17,12,11,9,11,10,9,94,94,88,1008,1006,1001,10,9,4,34,11,,13.97,6,Rain-Thunderstorm,104
2014-11-18,16,12,9,12,10,8,100,77,59,1009,1007,1004,19,10,10,37,19,55,1.02,3,Rain-Thunderstorm,246
2014-11-19,18,13,8,11,9,7,96,82,55,1022,1015,1009,31,11,8,35,14,,0.00,2,Fog-Thunderstorm,134
2014-11-20,16,11,6,11,8,5,100,87,57,1025,1023,1022,19,10,8,14,8,,0.00,1,Fog,123
2014-11-21,12,9,7,11,9,7,100,92,82,1024,1023,1022,11,9,5,13,10,,0.51,5,Rain,124
2014-11-22,15,13,11,13,12,10,94,91,82,1025,1023,1022,14,9,7,16,11,,0.25,5,Rain,117
2014-11-23,18,14,12,14,12,11,100,88,69,1027,1025,1024,19,10,8,14,10,,0.00,4,Fog,118
2014-11-24,17,13,9,14,12,9,100,92,79,1025,1023,1022,14,9,4,13,6,,0.00,4,Fog,124
2014-11-25,16,14,13,14,13,12,95,92,85,1023,1020,1018,10,8,3,13,8,,6.10,6,Rain,123
2014-11-26,17,15,13,15,13,12,95,93,86,1019,1015,1014,10,7,2,21,6,,3.05,6,Rain-Thunderstorm,126
2014-11-27,18,15,12,14,13,11,94,90,79,1014,1012,1011,14,9,4,21,11,,2.03,5,Rain-Thunderstorm,107
2014-11-28,16,14,13,13,12,10,95,84,60,1012,1010,1009,19,10,6,19,11,,0.25,6,Rain-Thunderstorm,107
2014-11-29,19,16,12,14,12,10,88,82,64,1012,1011,1010,19,11,10,26,13,,0.00,5,Rain,115
2014-11-30,18,16,14,14,13,11,94,81,60,1011,1007,1002,19,10,10,32,16,,0.00,6,Rain,121
2014-12-1,17,14,12,15,13,11,100,91,63,1002,1000,998,11,9,3,26,13,,21.08,5,Rain-Thunderstorm,93
2014-12-2,18,14,10,12,11,9,94,82,59,1005,1002,1001,14,10,10,16,6,,0.00,2,,122
2014-12-3,17,13,9,10,9,9,100,82,51,1010,1007,1004,19,11,10,23,8,,0.00,4,,139
2014-12-4,15,12,9,12,9,7,94,87,72,1013,1012,1010,14,10,10,21,13,,0.00,5,Rain,112
2014-12-5,15,12,10,11,9,9,94,86,67,1014,1013,1012,19,10,10,23,16,,0.25,5,Rain,108
2014-12-6,15,12,10,11,10,9,97,87,67,1014,1012,1011,19,10,6,26,14,,2.03,6,Rain-Thunderstorm,87
2014-12-7,14,11,7,11,9,6,100,90,72,1015,1014,1013,19,10,10,14,6,,0.00,4,Rain,129
2014-12-8,15,10,5,9,6,4,95,85,45,1017,1014,1012,19,11,10,23,5,,0.00,2,,111
2014-12-9,12,9,6,6,2,-2,93,62,31,1020,1013,1009,31,11,10,27,19,,0.00,2,,88
2014-12-10,14,8,3,6,2,-2,93,70,34,1022,1021,1019,18,11,10,14,8,,0.00,3,,117
2014-12-11,12,7,2,6,4,2,100,83,48,1020,1018,1017,19,11,10,14,10,,0.00,2,,120
2014-12-12,12,7,2,8,5,2,100,89,59,1022,1020,1019,19,10,8,16,8,,0.00,4,Rain,124
2014-12-13,13,10,7,11,9,7,100,92,82,1022,1021,1020,19,10,6,19,8,,1.02,6,Rain,102
2014-12-14,15,12,9,11,9,8,95,85,68,1022,1021,1020,19,11,10,21,11,,0.25,4,,109
2014-12-15,15,13,12,13,11,9,94,84,70,1022,1019,1016,11,10,6,26,16,,5.08,5,Rain,101
2014-12-16,13,11,9,11,9,8,100,89,72,1016,1010,1007,14,10,10,26,16,,0.00,5,Rain,96
2014-12-17,14,10,7,10,9,7,100,90,72,1014,1012,1008,26,10,6,13,5,,0.00,3,Fog,123
2014-12-18,16,11,6,10,8,5,100,89,57,1023,1019,1014,26,8,3,13,8,,0.00,2,Fog,120
2014-12-19,14,10,7,12,8,6,100,91,70,1025,1024,1023,19,9,5,11,5,,0.00,3,Fog,125
2014-12-20,15,12,9,12,10,8,100,91,77,1024,1022,1021,10,7,0,11,6,,0.00,4,Fog,121
2014-12-21,14,10,6,12,8,5,100,93,82,1031,1026,1023,19,4,0,13,5,,0.00,3,Fog,113
2014-12-22,12,7,2,9,6,2,100,89,70,1032,1031,1030,11,9,2,13,8,,0.00,3,Fog,131
2014-12-23,12,10,7,11,9,6,94,89,70,1031,1030,1029,19,10,10,13,5,,0.00,5,,258
2014-12-24,14,12,11,11,9,8,94,78,60,1029,1027,1026,19,10,10,19,10,,0.00,6,,257
2014-12-25,13,11,8,11,10,7,100,90,76,1026,1022,1019,19,10,2,11,6,,0.00,4,Fog,171
2014-12-26,14,8,3,7,3,-4,100,75,23,1023,1021,1018,31,6,1,23,8,,0.00,3,,108
2014-12-27,11,6,-1,10,3,-1,100,90,69,1023,1010,998,19,8,1,48,11,71,33.02,5,Fog-Rain-Thunderstorm,122
2014-12-28,9,5,1,3,1,-3,100,74,42,1014,1002,998,19,9,0,24,10,,0.00,2,Fog,92
2014-12-29,9,4,0,-1,-3,-7,87,61,22,1025,1022,1015,31,13,10,26,10,,0.00,2,,89
2014-12-30,6,1,-3,-1,-3,-6,100,61,36,1030,1028,1025,14,10,10,32,14,,0.00,2,,114
2014-12-31,5,1,-2,-1,-4,-8,93,64,33,1031,1028,1026,31,12,10,35,14,52,0.00,3,,102
File not shown (binary encoding).