Apologies if this seems like a duplicate D3 question. I've spent 2 days trying to figure out how to do this.

I'm trying to create a multi-line chart with the x-axis as an ordinal scale, and the y axis as a normal linear scale. Everything I've seen involves using time and linear scales combined and I can't seem to convert the examples to make them work how I want.

Here's my sample JSON data:

var data = 
[
    { "Supplier": "Supplier1", "Half": "2013 2H", "Value": 99.86047786 },
    { "Supplier": "Supplier1", "Half": "2013 1H", "Value": 93.86047786 },
    { "Supplier": "Supplier1", "Half": "2012 2H", "Value": 98.86047786 },
    { "Supplier": "Supplier1", "Half": "2012 1H", "Value": 96.86047786 },
    { "Supplier": "Supplier2", "Half": "2013 2H", "Value": 97.86047786 },
    { "Supplier": "Supplier2", "Half": "2013 1H",  "Value": 91.86047786 },
    { "Supplier": "Supplier2", "Half": "2012 2H","Value": 93.86047786 },
    { "Supplier": "Supplier2", "Half": "2012 1H", "Value": 94.86047786 },
    { "Supplier": "Supplier3", "Half": "2013 2H", "Value": 92.86047786 },
    { "Supplier": "Supplier3", "Half": "2013 1H", "Value": 91.86047786 },
    { "Supplier": "Supplier3", "Half": "2012 2H", "Value": 88.86047786 },
    { "Supplier": "Supplier3", "Half": "2012 1H", "Value": 87.86047786 },   
    { "Supplier": "Supplier4", "Half": "2013 2H", "Value": 88.86047786 },
    { "Supplier": "Supplier4", "Half": "2013 1H", "Value": 86.86047786 },
    { "Supplier": "Supplier4", "Half": "2012 2H", "Value": 83.86047786 },
    { "Supplier": "Supplier4", "Half": "2012 1H", "Value": 81.86047786 },   
];

And here's where I've gotten so far in trying to create the chart:

//Width and height
var margin = {top: 20, right: 20, bottom: 30, left: 40};           
var width = 600 - margin.left - margin.right;
var height= 500-margin.top -margin.bottom;
var w = width;
var h = height;

var xScale = d3.scale.ordinal()
    .domain(data.map(function (d) {return d.Half; }))
    .rangeRoundBands([margin.left, width], 0.05);

var xAxis = d3.svg.axis().scale(xScale).orient("bottom").tickSize(height - margin.bottom);

var yScale = d3.scale.linear()
    .domain([0, d3.max(data, function(d) {return d.Value; })])
    .range([h,0]);


//Create SVG element
var svg = d3.select("body")
    .append("svg")
    .attr("width", w)
    .attr("height", h);


svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + 0 + ")")
    .call(xAxis);

data = d3.nest().key(function(d) { return d.Supplier; }).entries(data); 

What I can't figure out is how to create the lines for the 4 different "suppliers" with the "Half" date buckets as the X coordinates and the "Value" as the Y coordinates. Ideally I would have 4 lines on the graph, one for each supplier, each with a different color.

Any help/direction would be greatly appreciated.

有帮助吗?

解决方案

This should get you started: http://jsfiddle.net/hU6r6/

Setting the domain of the xScale properly

// Find all the unique x-axis values
// Fortunately, alphabetical sorting of the values also yields
// the correct order
var xValues = d3.set(data.map(function (d) { return d.Half; })).values().sort();

// Set up the domain using only the unique values for the xAxis
var xScale = d3.scale.ordinal()
    .domain(xValues)
    // Setting the rangePoints instead of rangeBands
    .rangePoints([0, width], 0.5);

Append DOM elements tied to the data

// This is the same data as you have created
var supplierData = d3.nest().key(function(d) { return d.Supplier; }).entries(data); 

// Create a line object which will set the 'd' attributes for the paths
var line = d3.svg.line()
                  .interpolate("linear")
                  .x(function (d) { return xScale(d.Half); })
                  .y(function (d) { return yScale(d.Value); });

// To choose different colors
var colors = d3.scale.category10();

// The chart container
var gLines = svg.selectAll('g.chart-area').data([ supplierData ]);

gLines.enter()
  .append('g')
  .classed('chart-area', true)
  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ")");

// Our 'paths' which are the lines
var lines = gLines.selectAll('path.supplier').data(function (d) { return d; });

// Our 'paths' which are the lines
lines.enter()
  .append('path')
  .classed('supplier', true)
  // The data is of the form { key: 'SupplierX', values: [ ... ] }
  .attr('d', function (d) { return line(d.values); })
  .attr('fill', 'none')
  .attr('stroke', function (d, i) { return colors(i); })

Next steps

If you followed the tutorial, then you will see that the jsFiddle only implements the enter phase of the data. Perhaps that is enough for your purposes and update and exit phases are not needed. Nevertheless, you should follow the tutorial completely.

Apart from that,this graph is still bare-bone and lacks proper y-axis and labels for the colors, etc.

其他提示

You'll probably want to use an SVG path to represent each line. D3 has a line generator that can help with the line definition.

In it's simplest form it could look something like this with your data:

var line = d3.svg.line()
    .x(function(d) { return xScale(d.Half); })
    .y(function(d) { return yScale(d.Value); });

svg.selectAll("path")
    .data(data)
    .enter().append("path")
        .attr("d", function(d) { return line(d.values); });

You'll probably also want to set the fill and stroke styles to get the lines to look good and probably to color them individually using an ordinal color scale with Supplier as a domain.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top