Frederic Bastiat
Frederic Bastiat

Reputation: 693

TypeError: n is not a function

This is being caused by some sort of function problem where I am overriding an event parameter somewhere, correct? or an extraneous semi-colon?

Everything seems to load (e.g. CSS styling) on the page but I get this error. Can you spot where my problem is (are?)?

p.s. I am just using fiddle here for ease of use. I am hosting my own HTTP server so I know the CSV loads correctly.

https://jsfiddle.net/fredbastiat/hyLb2tym/

var margin = {top: 20, right: 20, bottom: 70, left: 40},
    width = 600 - margin.left - margin.right,
    height = 300 - margin.top - margin.bottom;

var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);

var xAxis = d3.axisBottom()
.scale(x)
.ticks(10);

var yAxis = d3.axisLeft()
.scale(y)
.ticks(10);


var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
.append("g")
    .attr("transform", 
      "translate(" + margin.left + "," + margin.top + ")");


d3.csv("Sales Export Friendly 2-14-2017.csv", function(error, sales) {
    if (error) throw error;
    /*sales.forEach(function(sale) {
        sale.BookingID = sale.BookingID;
        sale["Total Paid"] = sale["Total Paid"];
    });*/
    x.domain(sales.map(function(sale) { return sale.BookingID; }));
    y.domain([0, d3.max(sales, sales.map(function(sale) { return sale["Total Paid"]; }))]);

svg.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis)
.selectAll("text")
  .style("text-anchor", "end")
  .attr("dx", "-.8em")
  .attr("dy", "-.55em")
  .attr("transform", "rotate(-90)" );

svg.append("g")
  .attr("class", "y axis")
  .call(yAxis)
.append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 6)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("$ USD");

svg.selectAll("bar")
  .sales(sales)
.enter().append("rect")
  .style("fill", "steelblue")
  .attr("x", function(sale) { return x(sale.BookingID); })
  .attr("width", x.rangeBand())
  .attr("y", function(sale) { return y(sale["Total Paid"]); })
  .attr("height", function(sale) { return height - y(sale["Total Paid"]); });   

});

Upvotes: 1

Views: 1620

Answers (1)

Andrew Reid
Andrew Reid

Reputation: 38181

In the y domain, you don't need (sales, sales.map ... just (sales.map. Like so:

y.domain([0, d3.max(sales.map(function(sale){ return sale['Total Paid']; }))]);

That the error occurred before anything was drawn helps pinpoint that the error was in the scales, as everything is dependent on them.

Beyond that first error message, There is also an error when making your selection to append the bars. You want .data(sales) not .sales(sales).

Also, a d3.linearScale does not have a rangeBand method, you'll have to use a scaleBand, something like:

   var x = d3.scaleBand()
        .domain(sales.map(function(sale){ return sale.bookingID; }))
        .range([0, width])
        .paddingInner([0.1])

This scale selection is better in any event, as orders aren't a linear dimension, but one with discrete elements.

Altogether, it should give you something like:

var margin = {top: 20, right: 20, bottom: 70, left: 40},
		width = 600 - margin.left - margin.right,
		height = 300 - margin.top - margin.bottom;
	

   var sales = [
  	{bookingID:100,"Total Paid":100},
    {bookingID:101,"Total Paid":90},
    {bookingID:102,"Total Paid":100},
    {bookingID:103,"Total Paid":80},
    {bookingID:104,"Total Paid":150},
    {bookingID:105,"Total Paid":100},
    {bookingID:106,"Total Paid":160},
    {bookingID:107,"Total Paid":100}
  ];
  
	var svg = d3.select("body").append("svg")
		.attr("width", width + margin.left + margin.right)
		.attr("height", height + margin.top + margin.bottom)
	    .append("g")
		.attr("transform","translate("+margin.left+","+margin.top+")");
	
  var y = d3.scaleLinear()
      .range([height, 0])
      .domain([0, d3.max(sales.map(function(sale){ return sale['Total Paid']; }))]);
  
	var yAxis = d3.axisLeft()
    .scale(y)
    .ticks(10);
    
   var x = d3.scaleBand()
    	.domain(sales.map(function(sale){ return sale.bookingID; }))
    	.range([0, width])
    	.paddingInner([0.1]);
 
	var xAxis = d3.axisBottom()
    .scale(x)
	  .ticks(10);

	svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
    .selectAll("text")
      .style("text-anchor", "end")
      .attr("dx", "-.8em")
      .attr("dy", "-.55em")
      .attr("transform", "rotate(-90)" );

	svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text("$ USD");

	svg.selectAll("bar")
      .data(sales)
    .enter().append("rect")
      .style("fill", "steelblue")
      .attr("x", function(sale) { return x(sale.bookingID); })
      .attr("width", x.bandwidth())
      .attr("y", function(sale) { return y(sale["Total Paid"]); })
      .attr("height", function(sale) { return height - y(sale["Total Paid"]); });	
		
//	});
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
<div class="someclass">
  <h2>Create A Bar Chart With D3 JavaScript</h2>
  <div id="bar-chart">
  </div>
</div>

Upvotes: 1

Related Questions