Question

I am trying to develop a scatterplot using d3 but the domain for y-axis is confusing me. y-axis are gonna display patient names and x-axis display their appointment dates. x-axis are working fine, but y-axis are displaying only two patient names.

function graph()  {

    var num_patient = Object.keys(patientList).length;
    var patient_names = Object.keys(patientList);
    console.log(patient_names);

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

    x.domain(d3.extent(data, function(d) {return parseDate(d.dates); }));
    //y.domain(patient_names.map(function(d)  { return d.name;}));
    y.domain(patient_names);    

    console.log(y.domain());

    var xAxis = d3.svg.axis()
        .scale(x)
        .ticks(d3.time.year, 1)
        .orient("bottom");

    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left");

    var svg = d3.select("#punchcard")
            .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 + ")");

     svg.selectAll("dot")
            .data(data)
        .enter()
        .append("circle")
            .attr("r", 3.5)
            .attr("cx", function(d) { return x(d.date); })
            .attr("cy", function(d) { return y(d.value); });

     svg.append("g")            // Add the X Axis
            .attr("class", "x axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis);

    svg.append("g")         // Add the Y Axis
            .attr("class", "y axis")
            .call(yAxis);
}

console.log(patient_names) display the names correctly:

`["Andrew","Fred","Steve","John"]`

console.log(y.domain()) displays an extra undefined object:

["Andrew", "Fred","Steve" , "John", undefined]

But the y-axis only display Andrew at 0 and Fred at height h. How can I get to display all four names? I cannot hard code them as they are user input values. BTW: I am a beginner with d3 and js.

Thanks in advance!

Was it helpful?

Solution

With ordinal scales, you need to define the range points for the inputs explicitly (see the documentation). That is, you need to tell the scale explicitly which input value to map to which output. For example:

var y = d3.scale.ordinal()
          .domain(["Andrew","Fred","Steve","John"])
          .range([height, height * 2/3, height * 1/3, 0]);

You probably want to use the .rangePoints() method instead, which allows you to specify an interval that D3 automatically divides based on the number of values in the domain:

var y = d3.scale.ordinal()
          .domain(["Andrew","Fred","Steve","John"])
          .rangePoints([height, 0]);

Note that for .rangePoints() to work properly, you need to set the domain before the output range.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top