D3.js d3饼图的分组数据

D3.js d3饼图的分组数据,d3.js,D3.js,这里有个d3新手。我正在尝试将csv文件中的所有元素分组,以便在饼图上显示为单个序列 <script> var width = 960, height = 500, radius = Math.min(width, height) / 2; var color = d3.scale.ordinal() .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8

这里有个d3新手。我正在尝试将csv文件中的所有元素分组,以便在饼图上显示为单个序列

<script>
var width = 960,
    height = 500,
    radius = Math.min(width, height) / 2;

var color = d3.scale.ordinal()
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

var arc = d3.svg.arc()
    .outerRadius(radius - 10)
    .innerRadius(radius - 70);

var pie = d3.layout.pie()
    .sort(null)
    .value(function(d) { return d.count; });

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

d3.csv("data.csv", function(error, data) {

  var g = svg.selectAll(".arc")
      .data(pie(data))
      .enter().append("g")
      .attr("class", "arc");

  g.append("path")
      .attr("d", arc)
      .style("fill", function(d) { return color(d.data.colors); });

  g.append("text")
      .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
      .attr("dy", ".35em")
      .style("text-anchor", "middle")
      .text(function(d) { return d.data.colors; });
})
</script>
这是csv文件。(一个更大文件的简化版本,其中我将20-30个条目分组):

这就是我现在得到的:

我希望将红色元素和相应的计数分组,使其显示如下:

可能有一个简单的解决方案。这是d3脚本。没什么特别的,只是你是标准的饼图

<script>
var width = 960,
    height = 500,
    radius = Math.min(width, height) / 2;

var color = d3.scale.ordinal()
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

var arc = d3.svg.arc()
    .outerRadius(radius - 10)
    .innerRadius(radius - 70);

var pie = d3.layout.pie()
    .sort(null)
    .value(function(d) { return d.count; });

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

d3.csv("data.csv", function(error, data) {

  var g = svg.selectAll(".arc")
      .data(pie(data))
      .enter().append("g")
      .attr("class", "arc");

  g.append("path")
      .attr("d", arc)
      .style("fill", function(d) { return color(d.data.colors); });

  g.append("text")
      .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
      .attr("dy", ".35em")
      .style("text-anchor", "middle")
      .text(function(d) { return d.data.colors; });
})
</script>

可变宽度=960,
高度=500,
半径=数学最小值(宽度、高度)/2;
var color=d3.scale.ordinal()
.范围([“98abc5”、“8a89a6”、“7b6888”、“6b486b”、“a05d56”、“d0743c”、“ff8c00”);
var arc=d3.svg.arc()
.外层(半径-10)
.内半径(半径-70);
var pie=d3.layout.pie()
.sort(空)
.value(函数(d){返回d.count;});
var svg=d3.选择(“正文”).追加(“svg”)
.attr(“宽度”,宽度)
.attr(“高度”,高度)
.附加(“g”)
.attr(“变换”、“平移”(+width/2+)、“+height/2+”);
d3.csv(“data.csv”,函数(错误,数据){
var g=svg.selectAll(“.arc”)
.数据(pie(数据))
.enter().append(“g”)
.attr(“类”、“弧”);
g、 附加(“路径”)
.attr(“d”,弧)
.style(“fill”,函数(d){返回颜色(d.data.colors);});
g、 附加(“文本”)
.attr(“变换”,函数(d){return“translate”(+arc.centroid(d)+”);})
.attr(“dy”,“.35em”)
.style(“文本锚定”、“中间”)
.text(函数(d){返回d.data.colors;});
})

当我必须为d3执行数据转换任务时,我更喜欢在后端执行,因为您可以模拟数据并对转换引擎运行测试。然后你只是把数据发送到d3。也就是说:

(C#MVC Web Api示例)

public class RestaurantViewModel
{
公共列表餐厅数据{get;set;}
}
公共类餐厅数据系列
{
公共字符串Zipcode{get;set;}
公共列表数据系列{get;set;}
}
公共类ScoreDataPoint
{
公共字符串分数{get;set;}
公共整数计数{get;set;}
}
公共餐厅可视模型GetRestaurantSeries()
{
var csvConfiguration=新的csvConfiguration();
csvConfiguration.RegisterClassMap();
const string fileName=“餐厅检查得分图表.csv”;
使用(var streamReader=_fileSource.GetFile(文件名))
{
var csvReader=新csvReader(streamReader,CSV配置);
var restaurantDataPoints=csvReader.GetRecords().ToList();
可变Zipcode=
restaurantDataPoints.DistinctBy(point=>point.Zipcode).Select(point=>point.Zipcode.ToList();//不同的zips
var restaurantDataSeries=新列表();
var scoreList=新列表{“A”、“B”、“C”、“D”};
foreach(zipcodes中的var zipcode)
{
var currentRestaurantDataSeries=新RestaurantDataSeries
{
Zipcode=Zipcode,
DataSeries=新列表()
};
foreach(分数表中的var分数)
{
currentRestaurantDataSeries.DataSeries.Add(新的ScoreDataPoint
{
分数=分数,
计数=
餐厅数据点。计数(
point=>point.Zipcode==Zipcode&&ScoreConverter.GetScore(point.Score)==Score)
});
}
添加(currentRestaurantDataSeries);
}
返回新RestaurantViewModel{RestaurantData=RestaurantData Series};
}
}

然后我使用D3中的格式化列表,非常简单,无需使用javascript进行数据转换。但是,我发现在静态类型语言中使用数据要简单得多,我可以在编译时而不是运行时对名称和转换进行验证。如果您想要一个直接的
d3
解决方案,那么:

完整的例子

public class RestaurantViewModel
{
    public List<RestaurantDataSeries> RestaurantData { get; set; }
}
public class RestaurantDataSeries
{
    public string Zipcode { get; set; }
    public List<ScoreDataPoint> DataSeries { get; set; }
}

public class ScoreDataPoint
{
    public string Score { get; set; }
    public int Count { get; set; }
}

public RestaurantViewModel GetRestaurantSeries()
{
    var csvConfiguration = new CsvConfiguration();
    csvConfiguration.RegisterClassMap<RestaurantDataMap>();
    const string fileName = "Restaurant_Inspection_Scores_Chart.csv";
    using (var streamReader = _fileSource.GetFile(fileName))
    {
        var csvReader = new CsvReader(streamReader, csvConfiguration);
        var restaurantDataPoints = csvReader.GetRecords<RestaurantData>().ToList();
        var zipcodes =
            restaurantDataPoints.DistinctBy(point => point.Zipcode).Select(point => point.Zipcode).ToList(); //Distinct zips

        var restaurantDataSeries = new List<RestaurantDataSeries>();
        var scoreList = new List<string> {"A", "B", "C", "D"};
        foreach (var zipcode in zipcodes)
        {
            var currentRestaurantDataSeries = new RestaurantDataSeries
            {
                Zipcode = zipcode,
                DataSeries = new List<ScoreDataPoint>()
            };

            foreach (var score in scoreList)
            {

                currentRestaurantDataSeries.DataSeries.Add(new ScoreDataPoint
                {
                    Score = score,
                    Count =
                        restaurantDataPoints.Count(
                            point => point.Zipcode == zipcode && ScoreConverter.GetScore(point.Score) == score)
                });
            }
            restaurantDataSeries.Add(currentRestaurantDataSeries);
        }

        return new RestaurantViewModel {RestaurantData = restaurantDataSeries};
    }
}
d3.csv("data.csv", function(error, data) {
  var data = d3.nest()
    .key(function(d) {
      return d.colors;
    })
    .rollup(function(d) {
      return d3.sum(d, function(g) {
        return g.count;
      });
    }).entries(data);

...