{"action":"created","comment":{"url":"https://api.github.com/repos/palantir/plottable/pulls/comments/43440861","id":43440861,"diff_hunk":"@@ -1 +1,783 @@\n ///<reference path=\"../testReference.ts\" />\n+\n+describe(\"Plots\", () => {\n+  describe(\"Bar Plot\", () => {\n+    describe (\"orientations\", () => {\n+      it(\"rejects invalid orientations\", () => {\n+        assert.throws(() => new Plottable.Plots.Bar(\"diagonal\"), Error);\n+      });\n+\n+      it(\"defaults to vertical\", () => {\n+        let defaultPlot = new Plottable.Plots.Bar<number, number>();\n+        assert.strictEqual(defaultPlot.orientation(), \"vertical\", \"default Plots.Bar() are vertical\");\n+      });\n+\n+      it(\"sets orientation on construction\", () => {\n+        let verticalPlot = new Plottable.Plots.Bar<number, number>(\"vertical\");\n+        assert.strictEqual(verticalPlot.orientation(), \"vertical\", \"vertical Plots.Bar()\");\n+\n+        let horizontalPlot = new Plottable.Plots.Bar<number, number>(\"horizontal\");\n+        assert.strictEqual(horizontalPlot.orientation(), \"horizontal\", \"horizontal Plots.Bar()\");\n+      });\n+    });\n+\n+    const orientations = [Plottable.Plots.Bar.ORIENTATION_VERTICAL, Plottable.Plots.Bar.ORIENTATION_HORIZONTAL];\n+    orientations.forEach((orientation) => {\n+      const isVertical = orientation === Plottable.Plots.Bar.ORIENTATION_VERTICAL;\n+      const basePositionAttr = isVertical ? \"x\" : \"y\";\n+      const baseSizeAttr = isVertical ? \"width\" : \"height\";\n+      const valuePositionAttr = isVertical ? \"y\" : \"x\";\n+      const valueSizeAttr = isVertical ? \"height\" : \"width\";\n+\n+      describe(`rendering when ${orientation}`, () => {\n+        const data = [\n+          { base: \"A\", value: 1 },\n+          { base: \"B\", value: 0 },\n+          { base: \"C\", value: -1 }\n+        ];\n+\n+        let svg: d3.Selection<void>;\n+        let barPlot: Plottable.Plots.Bar<string | number, number | string>;\n+        let baseScale: Plottable.Scales.Category;\n+        let valueScale: Plottable.Scales.Linear;\n+        let dataset: Plottable.Dataset;\n+\n+        beforeEach(() => {\n+          svg = TestMethods.generateSVG();\n+          barPlot = new Plottable.Plots.Bar<string | number, number | string>(orientation);\n+          baseScale = new Plottable.Scales.Category();\n+          valueScale = new Plottable.Scales.Linear();\n+          if (orientation === Plottable.Plots.Bar.ORIENTATION_VERTICAL) {\n+            barPlot.x((d: any) => d.base, baseScale);\n+            barPlot.y((d: any) => d.value, valueScale);\n+          } else {\n+            barPlot.y((d: any) => d.base, baseScale);\n+            barPlot.x((d: any) => d.value, valueScale);\n+          }\n+          dataset = new Plottable.Dataset(data);\n+        });\n+\n+        function assertCorrectRendering() {\n+          const baseline = barPlot.content().select(\".baseline\");\n+          const scaledBaselineValue = valueScale.scale(<number> barPlot.baselineValue());\n+          assert.strictEqual(TestMethods.numAttr(baseline, valuePositionAttr + \"1\"), scaledBaselineValue,\n+            `baseline ${valuePositionAttr + \"1\"} is correct`);\n+          assert.strictEqual(TestMethods.numAttr(baseline, valuePositionAttr + \"2\"), scaledBaselineValue,\n+            `baseline ${valuePositionAttr + \"2\"} is correct`);\n+          assert.strictEqual(TestMethods.numAttr(baseline, basePositionAttr + \"1\"), 0,\n+            `baseline ${basePositionAttr + \"1\"} is correct`);\n+          assert.strictEqual(TestMethods.numAttr(baseline, basePositionAttr + \"2\"), TestMethods.numAttr(svg, baseSizeAttr),\n+            `baseline ${basePositionAttr + \"2\"} is correct`);\n+\n+          const bars = barPlot.content().selectAll(\"rect\");\n+          assert.strictEqual(bars.size(), data.length, \"One bar was created per data point\");\n+          bars.each(function(datum, index) {\n+            const bar = d3.select(this);\n+            const baseSize = TestMethods.numAttr(bar, baseSizeAttr);\n+            assert.closeTo(baseSize, baseScale.rangeBand(), window.Pixel_CloseTo_Requirement,\n+              `bar ${baseSizeAttr} is correct (index ${index})`);\n+\n+            const valueSize = TestMethods.numAttr(bar, valueSizeAttr);\n+            assert.closeTo(valueSize, Math.abs(valueScale.scale(datum.value) - scaledBaselineValue),\n+              window.Pixel_CloseTo_Requirement, `bar ${valueSizeAttr} is correct (index ${index})`);\n+\n+            const basePosition = TestMethods.numAttr(bar, basePositionAttr);\n+            assert.closeTo(basePosition, baseScale.scale(datum.base) - 0.5 * baseSize, window.Pixel_CloseTo_Requirement,\n+              `bar ${basePositionAttr} is correct (index ${index})`);\n+\n+            const valuePosition = TestMethods.numAttr(bar, valuePositionAttr);\n+            const isShifted = isVertical ? (datum.value > barPlot.baselineValue()) : (datum.value < barPlot.baselineValue());\n+            const expectedValuePosition = (isShifted) ? scaledBaselineValue - valueSize : scaledBaselineValue;\n+            assert.closeTo(valuePosition, expectedValuePosition, window.Pixel_CloseTo_Requirement,\n+              `bar ${valuePositionAttr} is correct (index ${index})`);\n+          });\n+        }\n+\n+        it(\"renders with no data\", () => {\n+          assert.doesNotThrow(() => barPlot.renderTo(svg), Error);\n+          assert.strictEqual(barPlot.width(), TestMethods.numAttr(svg, \"width\"), \"was allocated width\");\n+          assert.strictEqual(barPlot.height(), TestMethods.numAttr(svg, \"height\"), \"was allocated height\");\n+        });\n+\n+        it(\"draws bars and baseline in correct positions\", () => {\n+          barPlot.addDataset(dataset);\n+          barPlot.renderTo(svg);\n+\n+          assertCorrectRendering();\n+        });\n+\n+        it(\"rerenders correctly when the baseline value is changed\", () => {\n+          barPlot.addDataset(dataset);\n+          barPlot.renderTo(svg);\n+\n+          barPlot.baselineValue(1);\n+          assertCorrectRendering();\n+        });\n+\n+        it(\"can autorange value scale based on visible points on base scale\", () => {\n+          const firstTwoBaseValues = [data[0].base, data[1].base ];\n+          valueScale.padProportion(0);\n+          baseScale.domain(firstTwoBaseValues);\n+          barPlot.addDataset(dataset);\n+          barPlot.autorangeMode(valuePositionAttr);\n+          barPlot.renderTo(svg);\n+\n+          const valueScaleDomain = valueScale.domain();\n+          const expectedValueDomainMin = Math.min(data[0].value, data[1].value);\n+          const expectedValueDomainMax = Math.max(data[0].value, data[1].value);\n+          assert.strictEqual(valueScaleDomain[0], expectedValueDomainMin, \"lower bound of domain set based on visible points\");\n+          assert.strictEqual(valueScaleDomain[1], expectedValueDomainMax, \"upper bound of domain set based on visible points\");\n+        });\n+\n+        it(\"doesn't show values from outside the base scale's domain\", () => {\n+          baseScale.domain([\"-A\"]);\n+          barPlot.addDataset(dataset);\n+          barPlot.renderTo(svg);\n+\n+          assert.strictEqual(barPlot.content().selectAll(\"rect\").size(), 0, \"draws no bars when the domain contains no data points\");\n+        });\n+\n+        afterEach(function() {\n+          if (this.currentTest.state === \"passed\") {\n+            barPlot.destroy();\n+            svg.remove();\n+          }\n+        });\n+      });\n+\n+      describe(`autodomaining when ${orientation}`, () => {\n+        let svg: d3.Selection<void>;\n+        let baseScale: Plottable.Scales.Linear;\n+        let valueScale: Plottable.Scales.Linear;\n+        let barPlot: Plottable.Plots.Bar<number, number>;\n+\n+        const baseAccessor = (d: any) => d.base;\n+        const valueAccessor = (d: any) => d.value;\n+\n+        beforeEach(() => {\n+          svg = TestMethods.generateSVG();\n+          barPlot = new Plottable.Plots.Bar<number, number>(orientation);\n+          baseScale = new Plottable.Scales.Linear();\n+          valueScale = new Plottable.Scales.Linear();\n+          if (orientation === Plottable.Plots.Bar.ORIENTATION_VERTICAL) {\n+            barPlot.x(baseAccessor, baseScale);\n+            barPlot.y(valueAccessor, valueScale);\n+          } else {\n+            barPlot.y(baseAccessor, baseScale);\n+            barPlot.x(valueAccessor, valueScale);\n+          }\n+        });\n+\n+        it(\"computes the base scale domain correctly when there is only one data point\", () => {\n+          const singlePointData = [\n+            { base: baseScale.domain()[1] + 10, value: 5 }\n+          ];\n+          barPlot.addDataset(new Plottable.Dataset(singlePointData));\n+          barPlot.renderTo(svg);\n+          const baseScaleDomain = baseScale.domain();\n+          assert.operator(baseScaleDomain[0], \"<=\", singlePointData[0].base, \"lower end of base domain is less than the value\");\n+          assert.operator(baseScaleDomain[1], \">=\", singlePointData[0].base, \"upper end of base domain is greater than the value\");\n+        });\n+\n+        it(\"base scale domain does not change when autoDomain is called more than once\", () => {\n+          const data = [\n+            { base: 0, value: 1 },\n+            { base: 1, value: 2 }\n+          ];\n+          barPlot.addDataset(new Plottable.Dataset(data));\n+          barPlot.renderTo(svg);\n+\n+          const baseDomainAfterRendering = baseScale.domain();\n+          baseScale.autoDomain();\n+          const baseDomainAfterAutoDomaining = baseScale.domain();\n+          assert.deepEqual(baseDomainAfterRendering, baseDomainAfterAutoDomaining, \"calling autoDomain() again does not change the domain\");\n+        });\n+\n+        afterEach(function() {\n+          if (this.currentTest.state === \"passed\") {\n+            barPlot.destroy();\n+            svg.remove();\n+          }\n+        });\n+      });\n+\n+      describe(`auto bar width calculation when ${orientation}`, () => {\n+        const scaleTypes = [\"Linear\", \"ModifiedLog\", \"Time\"];\n+        scaleTypes.forEach((scaleType) => {\n+          describe(`using a ${scaleType} base Scale`, () => {\n+            let svg: d3.Selection<void>;\n+            let barPlot: Plottable.Plots.Bar<number | Date, number | Date>;\n+            let baseScale: Plottable.QuantitativeScale<number | Date>;\n+            let valueScale: Plottable.Scales.Linear;\n+            let dataset: Plottable.Dataset;\n+\n+            beforeEach(() => {\n+              svg = TestMethods.generateSVG();\n+              barPlot = new Plottable.Plots.Bar<number | Date, number | Date>(orientation);\n+\n+              switch (scaleType) {\n+                case \"Linear\":\n+                  baseScale = new Plottable.Scales.Linear();\n+                  break;\n+                case \"ModifiedLog\":\n+                  baseScale = new Plottable.Scales.ModifiedLog();\n+                  break;\n+                case \"Time\":\n+                  baseScale = new Plottable.Scales.Time();\n+                  break;\n+                default:\n+                  throw new Error(\"unexpected base Scale type\");\n+              }\n+              valueScale = new Plottable.Scales.Linear();\n+\n+              const baseAccessor = (scaleType === \"Time\") ? (d: any) => new Date(d.base) : (d: any) => d.base;\n+              const valueAccessor = (d: any) => d.value;\n+              if (orientation === Plottable.Plots.Bar.ORIENTATION_VERTICAL) {\n+                barPlot.x(baseAccessor, baseScale);\n+                barPlot.y(valueAccessor, valueScale);\n+              } else {\n+                barPlot.y(baseAccessor, baseScale);\n+                barPlot.x(valueAccessor, valueScale);\n+              }\n+              dataset = new Plottable.Dataset();\n+              barPlot.addDataset(dataset);\n+              barPlot.renderTo(svg);\n+            });\n+\n+            it(\"computes a sensible width\", () => {\n+              const data = [\n+                { base: 1, value: 5 },\n+                { base: 10, value: 2 },\n+                { base: 100, value: 4 }\n+              ];\n+              dataset.data(data);\n+\n+              const closestSeparation = Math.abs(baseScale.scale(data[1].base) - baseScale.scale(data[0].base));\n+              const bars = barPlot.content().selectAll(\"rect\");\n+              assert.strictEqual(bars.size(), data.length, \"one bar was drawn per datum\");\n+              bars.each(function() {\n+                const bar = d3.select(this);\n+                const barSize = TestMethods.numAttr(bar, baseSizeAttr);\n+                assert.operator(barSize, \"<=\", closestSeparation, \"bar width is less than the closest distance between values\");\n+                assert.operator(barSize, \">=\", 0.5 * closestSeparation,\n+                  \"bar width is greater than half the closest distance between values\");\n+              });\n+            });\n+\n+            it(\"accounts for the bar width when autoDomaining the base scale\", () => {\n+              const data = [\n+                { base: 1, value: 5 },\n+                { base: 10, value: 2 },\n+                { base: 100, value: 4 }\n+              ];\n+              dataset.data(data);\n+\n+              const bars = barPlot.content().selectAll(\"rect\");\n+              assert.strictEqual(bars.size(), data.length, \"one bar was drawn per datum\");\n+              const svgSize = TestMethods.numAttr(svg, baseSizeAttr);\n+              bars.each(function() {\n+                const bar = d3.select(this);\n+                const barPosition = TestMethods.numAttr(bar, basePositionAttr);\n+                const barSize = TestMethods.numAttr(bar, baseSizeAttr);\n+                assert.operator(barPosition, \">=\", 0, `bar is within visible area (${basePositionAttr})`);\n+                assert.operator(barPosition, \"<=\", svgSize, `bar is within visible area (${basePositionAttr})`);\n+                assert.operator(barPosition + barSize, \">=\", 0, `bar is within visible area (${baseSizeAttr})`);\n+                assert.operator(barPosition + barSize, \"<=\", svgSize, `bar is within visible area (${baseSizeAttr})`);\n+              });\n+            });\n+\n+            it(\"does not crash when given bad data\", () => {\n+              const badData: any = [\n+                {},\n+                { base: null, value: null }\n+              ];\n+              assert.doesNotThrow(() => dataset.data(badData), Error);\n+            });\n+\n+            it(\"computes a sensible width when given only one datum\", () => {\n+              const singleDatumData = [\n+                { base: 1, value: 5 }\n+              ];\n+              dataset.data(singleDatumData);\n+\n+              const bar = barPlot.content().select(\"rect\");\n+              const barSize = TestMethods.numAttr(bar, baseSizeAttr);\n+              const svgSize = TestMethods.numAttr(svg, baseSizeAttr);\n+              assert.operator(barSize, \">=\", svgSize / 4, \"bar is larger than 1/4 of the available space\");\n+              assert.operator(barSize, \"<=\", svgSize / 2, \"bar is smaller than half the available space\");\n+            });\n+\n+            it(\"computes a sensible width when given repeated base value\", () => {\n+              const repeatedBaseData = [\n+                { base: 1, value: 5 },\n+                { base: 1, value: -5 }\n+              ];\n+              dataset.data(repeatedBaseData);\n+\n+              const bars = barPlot.content().selectAll(\"rect\");\n+              assert.strictEqual(bars.size(), repeatedBaseData.length, \"one bar was drawn per datum\");\n+              const svgSize = TestMethods.numAttr(svg, baseSizeAttr);\n+              bars.each(function() {\n+                const bar = d3.select(this);\n+                const barSize = TestMethods.numAttr(bar, baseSizeAttr);\n+                assert.operator(barSize, \">=\", svgSize / 4, \"bar is larger than 1/4 of the available space\");\n+                assert.operator(barSize, \"<=\", svgSize / 2, \"bar is smaller than half the available space\");\n+              });\n+            });\n+\n+            it(\"computes a sensible width when given unsorted data\", () => {\n+              const unsortedData = [\n+                { base: 10, value: 2 },\n+                { base: 1, value: 5 },\n+                { base: 100, value: 4 }\n+              ];\n+              dataset.data(unsortedData);\n+\n+              const closestSeparation = Math.abs(baseScale.scale(unsortedData[1].base) - baseScale.scale(unsortedData[0].base));\n+              const bars = barPlot.content().selectAll(\"rect\");\n+              assert.strictEqual(bars.size(), unsortedData.length, \"one bar was drawn per datum\");\n+              bars.each(function() {\n+                const bar = d3.select(this);\n+                const barSize = TestMethods.numAttr(bar, baseSizeAttr);\n+                assert.operator(barSize, \"<=\", closestSeparation, \"bar width is less than the closest distance between values\");\n+                assert.operator(barSize, \">=\", 0.5 * closestSeparation,\n+                  \"bar width is greater than half the closest distance between values\");\n+              });\n+            });\n+\n+            afterEach(function() {\n+              if (this.currentTest.state === \"passed\") {\n+                barPlot.destroy();\n+                svg.remove();\n+              }\n+            });\n+          });\n+        });\n+      });\n+\n+      describe(`labels when ${orientation}`, () => {\n+        const data = [\n+          { base: -4, value: -4 },\n+          { base: -2, value: -0.1},\n+          { base: 0, value: 0 },\n+          { base: 2, value: 0.1 },\n+          { base: 4, value: 4 }\n+        ];\n+        const DEFAULT_DOMAIN = [-5, 5];\n+\n+        let svg: d3.Selection<void>;\n+        let baseScale: Plottable.Scales.Linear;\n+        let valueScale: Plottable.Scales.Linear;\n+        let barPlot: Plottable.Plots.Bar<number, number>;\n+        let dataset: Plottable.Dataset;\n+\n+        beforeEach(() => {\n+          svg = TestMethods.generateSVG();\n+          barPlot = new Plottable.Plots.Bar<number, number>(orientation);\n+          baseScale = new Plottable.Scales.Linear();\n+          baseScale.domain(DEFAULT_DOMAIN);\n+          valueScale = new Plottable.Scales.Linear();\n+          valueScale.domain(DEFAULT_DOMAIN);\n+          if (orientation === Plottable.Plots.Bar.ORIENTATION_VERTICAL) {\n+            barPlot.x((d: any) => d.base, baseScale);\n+            barPlot.y((d: any) => d.value, valueScale);\n+          } else {\n+            barPlot.y((d: any) => d.base, baseScale);\n+            barPlot.x((d: any) => d.value, valueScale);\n+          }\n+          dataset = new Plottable.Dataset(data);\n+          barPlot.addDataset(dataset);\n+          barPlot.renderTo(svg);\n+        });\n+\n+        function getCenterOfText(textNode: SVGElement) {\n+          const plotBoundingClientRect = (<SVGElement> barPlot.background().node()).getBoundingClientRect();\n+          const labelBoundingClientRect = textNode.getBoundingClientRect();\n+\n+          return {\n+            x: (labelBoundingClientRect.left + labelBoundingClientRect.right) / 2 - plotBoundingClientRect.left,\n+            y: (labelBoundingClientRect.top + labelBoundingClientRect.bottom) / 2 - plotBoundingClientRect.top\n+          };\n+        };\n+\n+        it(\"does not show labels by default\", () => {\n+          const texts = barPlot.content().selectAll(\"text\");\n+          assert.strictEqual(texts.size(), 0, \"by default, no texts are drawn\");\n+        });\n+\n+        it(\"draws one label per datum\", () => {\n+          barPlot.labelsEnabled(true);\n+          barPlot.labelsEnabled(true);","path":"test/plots/barPlotTests.ts","position":410,"original_position":410,"commit_id":"f5f123ab9ccd41dedeb863868ecab371d63e7db5","original_commit_id":"f5f123ab9ccd41dedeb863868ecab371d63e7db5","user":{"login":"bluong","id":1448299,"avatar_url":"https://avatars.githubusercontent.com/u/1448299?v=3","gravatar_id":"","url":"https://api.github.com/users/bluong","html_url":"https://github.com/bluong","followers_url":"https://api.github.com/users/bluong/followers","following_url":"https://api.github.com/users/bluong/following{/other_user}","gists_url":"https://api.github.com/users/bluong/gists{/gist_id}","starred_url":"https://api.github.com/users/bluong/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bluong/subscriptions","organizations_url":"https://api.github.com/users/bluong/orgs","repos_url":"https://api.github.com/users/bluong/repos","events_url":"https://api.github.com/users/bluong/events{/privacy}","received_events_url":"https://api.github.com/users/bluong/received_events","type":"User","site_admin":false},"body":"Why double set?","created_at":"2015-10-29T20:37:08Z","updated_at":"2015-10-29T20:37:08Z","html_url":"https://github.com/palantir/plottable/pull/2942#discussion_r43440861","pull_request_url":"https://api.github.com/repos/palantir/plottable/pulls/2942","_links":{"self":{"href":"https://api.github.com/repos/palantir/plottable/pulls/comments/43440861"},"html":{"href":"https://github.com/palantir/plottable/pull/2942#discussion_r43440861"},"pull_request":{"href":"https://api.github.com/repos/palantir/plottable/pulls/2942"}}},"pull_request":{"url":"https://api.github.com/repos/palantir/plottable/pulls/2942","id":49172126,"html_url":"https://github.com/palantir/plottable/pull/2942","diff_url":"https://github.com/palantir/plottable/pull/2942.diff","patch_url":"https://github.com/palantir/plottable/pull/2942.patch","issue_url":"https://api.github.com/repos/palantir/plottable/issues/2942","number":2942,"state":"open","locked":false,"title":"[DO NOT MERGE] Bar Plot tests for review","user":{"login":"jtlan","id":1440449,"avatar_url":"https://avatars.githubusercontent.com/u/1440449?v=3","gravatar_id":"","url":"https://api.github.com/users/jtlan","html_url":"https://github.com/jtlan","followers_url":"https://api.github.com/users/jtlan/followers","following_url":"https://api.github.com/users/jtlan/following{/other_user}","gists_url":"https://api.github.com/users/jtlan/gists{/gist_id}","starred_url":"https://api.github.com/users/jtlan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jtlan/subscriptions","organizations_url":"https://api.github.com/users/jtlan/orgs","repos_url":"https://api.github.com/users/jtlan/repos","events_url":"https://api.github.com/users/jtlan/events{/privacy}","received_events_url":"https://api.github.com/users/jtlan/received_events","type":"User","site_admin":false},"body":"#2940 contains all the commits that actually create this change, but the diff is too large for Github to view.\r\n\r\nSince basically every line was replaced, this branch was created to show the effect of the change.\r\n\r\n# DO NOT MERGE.","created_at":"2015-10-29T17:24:13Z","updated_at":"2015-10-29T20:37:08Z","closed_at":null,"merged_at":null,"merge_commit_sha":"52db838b03ecae137755447fd17913f3e5456c17","assignee":{"login":"bluong","id":1448299,"avatar_url":"https://avatars.githubusercontent.com/u/1448299?v=3","gravatar_id":"","url":"https://api.github.com/users/bluong","html_url":"https://github.com/bluong","followers_url":"https://api.github.com/users/bluong/followers","following_url":"https://api.github.com/users/bluong/following{/other_user}","gists_url":"https://api.github.com/users/bluong/gists{/gist_id}","starred_url":"https://api.github.com/users/bluong/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bluong/subscriptions","organizations_url":"https://api.github.com/users/bluong/orgs","repos_url":"https://api.github.com/users/bluong/repos","events_url":"https://api.github.com/users/bluong/events{/privacy}","received_events_url":"https://api.github.com/users/bluong/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/palantir/plottable/pulls/2942/commits","review_comments_url":"https://api.github.com/repos/palantir/plottable/pulls/2942/comments","review_comment_url":"https://api.github.com/repos/palantir/plottable/pulls/comments{/number}","comments_url":"https://api.github.com/repos/palantir/plottable/issues/2942/comments","statuses_url":"https://api.github.com/repos/palantir/plottable/statuses/f5f123ab9ccd41dedeb863868ecab371d63e7db5","head":{"label":"palantir:2634review-addTests","ref":"2634review-addTests","sha":"f5f123ab9ccd41dedeb863868ecab371d63e7db5","user":{"login":"palantir","id":303157,"avatar_url":"https://avatars.githubusercontent.com/u/303157?v=3","gravatar_id":"","url":"https://api.github.com/users/palantir","html_url":"https://github.com/palantir","followers_url":"https://api.github.com/users/palantir/followers","following_url":"https://api.github.com/users/palantir/following{/other_user}","gists_url":"https://api.github.com/users/palantir/gists{/gist_id}","starred_url":"https://api.github.com/users/palantir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/palantir/subscriptions","organizations_url":"https://api.github.com/users/palantir/orgs","repos_url":"https://api.github.com/users/palantir/repos","events_url":"https://api.github.com/users/palantir/events{/privacy}","received_events_url":"https://api.github.com/users/palantir/received_events","type":"Organization","site_admin":false},"repo":{"id":16149854,"name":"plottable","full_name":"palantir/plottable","owner":{"login":"palantir","id":303157,"avatar_url":"https://avatars.githubusercontent.com/u/303157?v=3","gravatar_id":"","url":"https://api.github.com/users/palantir","html_url":"https://github.com/palantir","followers_url":"https://api.github.com/users/palantir/followers","following_url":"https://api.github.com/users/palantir/following{/other_user}","gists_url":"https://api.github.com/users/palantir/gists{/gist_id}","starred_url":"https://api.github.com/users/palantir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/palantir/subscriptions","organizations_url":"https://api.github.com/users/palantir/orgs","repos_url":"https://api.github.com/users/palantir/repos","events_url":"https://api.github.com/users/palantir/events{/privacy}","received_events_url":"https://api.github.com/users/palantir/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/palantir/plottable","description":"A library of modular chart components, built on D3","fork":false,"url":"https://api.github.com/repos/palantir/plottable","forks_url":"https://api.github.com/repos/palantir/plottable/forks","keys_url":"https://api.github.com/repos/palantir/plottable/keys{/key_id}","collaborators_url":"https://api.github.com/repos/palantir/plottable/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/palantir/plottable/teams","hooks_url":"https://api.github.com/repos/palantir/plottable/hooks","issue_events_url":"https://api.github.com/repos/palantir/plottable/issues/events{/number}","events_url":"https://api.github.com/repos/palantir/plottable/events","assignees_url":"https://api.github.com/repos/palantir/plottable/assignees{/user}","branches_url":"https://api.github.com/repos/palantir/plottable/branches{/branch}","tags_url":"https://api.github.com/repos/palantir/plottable/tags","blobs_url":"https://api.github.com/repos/palantir/plottable/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/palantir/plottable/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/palantir/plottable/git/refs{/sha}","trees_url":"https://api.github.com/repos/palantir/plottable/git/trees{/sha}","statuses_url":"https://api.github.com/repos/palantir/plottable/statuses/{sha}","languages_url":"https://api.github.com/repos/palantir/plottable/languages","stargazers_url":"https://api.github.com/repos/palantir/plottable/stargazers","contributors_url":"https://api.github.com/repos/palantir/plottable/contributors","subscribers_url":"https://api.github.com/repos/palantir/plottable/subscribers","subscription_url":"https://api.github.com/repos/palantir/plottable/subscription","commits_url":"https://api.github.com/repos/palantir/plottable/commits{/sha}","git_commits_url":"https://api.github.com/repos/palantir/plottable/git/commits{/sha}","comments_url":"https://api.github.com/repos/palantir/plottable/comments{/number}","issue_comment_url":"https://api.github.com/repos/palantir/plottable/issues/comments{/number}","contents_url":"https://api.github.com/repos/palantir/plottable/contents/{+path}","compare_url":"https://api.github.com/repos/palantir/plottable/compare/{base}...{head}","merges_url":"https://api.github.com/repos/palantir/plottable/merges","archive_url":"https://api.github.com/repos/palantir/plottable/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/palantir/plottable/downloads","issues_url":"https://api.github.com/repos/palantir/plottable/issues{/number}","pulls_url":"https://api.github.com/repos/palantir/plottable/pulls{/number}","milestones_url":"https://api.github.com/repos/palantir/plottable/milestones{/number}","notifications_url":"https://api.github.com/repos/palantir/plottable/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/palantir/plottable/labels{/name}","releases_url":"https://api.github.com/repos/palantir/plottable/releases{/id}","created_at":"2014-01-22T19:29:19Z","updated_at":"2015-10-29T19:06:47Z","pushed_at":"2015-10-29T18:57:14Z","git_url":"git://github.com/palantir/plottable.git","ssh_url":"git@github.com:palantir/plottable.git","clone_url":"https://github.com/palantir/plottable.git","svn_url":"https://github.com/palantir/plottable","homepage":"plottablejs.org","size":140522,"stargazers_count":781,"watchers_count":781,"language":"TypeScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":82,"mirror_url":null,"open_issues_count":241,"forks":82,"open_issues":241,"watchers":781,"default_branch":"develop"}},"base":{"label":"palantir:2634review","ref":"2634review","sha":"bf05f74f900d81265fc6510319805704332aeb57","user":{"login":"palantir","id":303157,"avatar_url":"https://avatars.githubusercontent.com/u/303157?v=3","gravatar_id":"","url":"https://api.github.com/users/palantir","html_url":"https://github.com/palantir","followers_url":"https://api.github.com/users/palantir/followers","following_url":"https://api.github.com/users/palantir/following{/other_user}","gists_url":"https://api.github.com/users/palantir/gists{/gist_id}","starred_url":"https://api.github.com/users/palantir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/palantir/subscriptions","organizations_url":"https://api.github.com/users/palantir/orgs","repos_url":"https://api.github.com/users/palantir/repos","events_url":"https://api.github.com/users/palantir/events{/privacy}","received_events_url":"https://api.github.com/users/palantir/received_events","type":"Organization","site_admin":false},"repo":{"id":16149854,"name":"plottable","full_name":"palantir/plottable","owner":{"login":"palantir","id":303157,"avatar_url":"https://avatars.githubusercontent.com/u/303157?v=3","gravatar_id":"","url":"https://api.github.com/users/palantir","html_url":"https://github.com/palantir","followers_url":"https://api.github.com/users/palantir/followers","following_url":"https://api.github.com/users/palantir/following{/other_user}","gists_url":"https://api.github.com/users/palantir/gists{/gist_id}","starred_url":"https://api.github.com/users/palantir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/palantir/subscriptions","organizations_url":"https://api.github.com/users/palantir/orgs","repos_url":"https://api.github.com/users/palantir/repos","events_url":"https://api.github.com/users/palantir/events{/privacy}","received_events_url":"https://api.github.com/users/palantir/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/palantir/plottable","description":"A library of modular chart components, built on D3","fork":false,"url":"https://api.github.com/repos/palantir/plottable","forks_url":"https://api.github.com/repos/palantir/plottable/forks","keys_url":"https://api.github.com/repos/palantir/plottable/keys{/key_id}","collaborators_url":"https://api.github.com/repos/palantir/plottable/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/palantir/plottable/teams","hooks_url":"https://api.github.com/repos/palantir/plottable/hooks","issue_events_url":"https://api.github.com/repos/palantir/plottable/issues/events{/number}","events_url":"https://api.github.com/repos/palantir/plottable/events","assignees_url":"https://api.github.com/repos/palantir/plottable/assignees{/user}","branches_url":"https://api.github.com/repos/palantir/plottable/branches{/branch}","tags_url":"https://api.github.com/repos/palantir/plottable/tags","blobs_url":"https://api.github.com/repos/palantir/plottable/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/palantir/plottable/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/palantir/plottable/git/refs{/sha}","trees_url":"https://api.github.com/repos/palantir/plottable/git/trees{/sha}","statuses_url":"https://api.github.com/repos/palantir/plottable/statuses/{sha}","languages_url":"https://api.github.com/repos/palantir/plottable/languages","stargazers_url":"https://api.github.com/repos/palantir/plottable/stargazers","contributors_url":"https://api.github.com/repos/palantir/plottable/contributors","subscribers_url":"https://api.github.com/repos/palantir/plottable/subscribers","subscription_url":"https://api.github.com/repos/palantir/plottable/subscription","commits_url":"https://api.github.com/repos/palantir/plottable/commits{/sha}","git_commits_url":"https://api.github.com/repos/palantir/plottable/git/commits{/sha}","comments_url":"https://api.github.com/repos/palantir/plottable/comments{/number}","issue_comment_url":"https://api.github.com/repos/palantir/plottable/issues/comments{/number}","contents_url":"https://api.github.com/repos/palantir/plottable/contents/{+path}","compare_url":"https://api.github.com/repos/palantir/plottable/compare/{base}...{head}","merges_url":"https://api.github.com/repos/palantir/plottable/merges","archive_url":"https://api.github.com/repos/palantir/plottable/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/palantir/plottable/downloads","issues_url":"https://api.github.com/repos/palantir/plottable/issues{/number}","pulls_url":"https://api.github.com/repos/palantir/plottable/pulls{/number}","milestones_url":"https://api.github.com/repos/palantir/plottable/milestones{/number}","notifications_url":"https://api.github.com/repos/palantir/plottable/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/palantir/plottable/labels{/name}","releases_url":"https://api.github.com/repos/palantir/plottable/releases{/id}","created_at":"2014-01-22T19:29:19Z","updated_at":"2015-10-29T19:06:47Z","pushed_at":"2015-10-29T18:57:14Z","git_url":"git://github.com/palantir/plottable.git","ssh_url":"git@github.com:palantir/plottable.git","clone_url":"https://github.com/palantir/plottable.git","svn_url":"https://github.com/palantir/plottable","homepage":"plottablejs.org","size":140522,"stargazers_count":781,"watchers_count":781,"language":"TypeScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":82,"mirror_url":null,"open_issues_count":241,"forks":82,"open_issues":241,"watchers":781,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/palantir/plottable/pulls/2942"},"html":{"href":"https://github.com/palantir/plottable/pull/2942"},"issue":{"href":"https://api.github.com/repos/palantir/plottable/issues/2942"},"comments":{"href":"https://api.github.com/repos/palantir/plottable/issues/2942/comments"},"review_comments":{"href":"https://api.github.com/repos/palantir/plottable/pulls/2942/comments"},"review_comment":{"href":"https://api.github.com/repos/palantir/plottable/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/palantir/plottable/pulls/2942/commits"},"statuses":{"href":"https://api.github.com/repos/palantir/plottable/statuses/f5f123ab9ccd41dedeb863868ecab371d63e7db5"}}}}