如何使用 D3 导航嵌套的 JSON 对象?

班迪

在我的 REACT 应用程序中,我正在读取 JSON 响应(使用axis),我使用react-faux-dom其传递给组件,以尝试重新创建 Mike Bostock 的多系列折线图(使用 D3 v4)。

console.log(apiData)在我的组件中运行显示了我所期望的对象 - 然而,我已经尝试了我能想到的一切,我能得到的最好的是空的 X 和 Y 轴(以及我<g>试图用来获取的“便签本”元素对我正在使用的内容的一些见解)。

有人可以指导我做错什么吗?


我传入的 JSON 对象:

{
    "roles": [
    {
        "AA": [
        {
        "date": "20150101",
        "total": 6.0
        },
        {
        "date": "20150201",
        "total": 14.5
        },
        {
        "date": "20150301",
        "total": 14.5
        }],
        "AB": [
        {
        "date": "20150301",
        "total": 1.6
        },
        {
        "date": "20150401",
        "total": 1.6
        },
        {
        "date": "20150501",
        "total": 7.24
        }]
    }]
}

我的主App.js文件调用组件:

import React, { Component } from 'react';
import './App.css';
import axios from 'axios';
import { MyD3ReactComponentExport } from './D3Timeseries'


class App extends Component {

    /* ... assign API response to "apiResponse" */

    render() {
        const {
            apiResponse
        } = this.state

        return (
            <div className="App">
                <button onClick={this.requestData}>Refresh Data</button>
                <MyD3ReactComponentExport apiData={apiResponse} />
            </div>
        );
    }
}

我的 react-faux-dom D3 组件

import React from 'react'
import * as d3 from 'd3'
import PropTypes from 'prop-types'
import { withFauxDOM } from 'react-faux-dom'

class MyD3ReactComponent extends React.Component {

    constructor (props) {
        super(props)
        this.renderD3 = this.renderD3.bind(this)
        this.updateD3 = this.updateD3.bind(this)
    }

    componentDidMount () {
        this.renderD3()
    }

    componentDidUpdate (prevProps, prevState) {
        if (this.props.data !== prevProps.data) {
            this.updateD3()
        }
    }


    render () {
        return (
            <div>
                <h2>Amazing timeseries:</h2>
                {this.props.myChart}
            </div>
        )
    }



    renderD3() {
        const {
           apiData
        } = this.props

        let faux = this.props.connectFauxDOM('div', 'myChart');

        let svg = d3.select(faux).append('svg')
            .attr("width",960)
            .attr("height",500);

        let margin = {top: 20, right: 80, bottom: 30, left: 50},
            width = svg.attr("width") - margin.left - margin.right,
            height = svg.attr("height") - margin.top - margin.bottom,
            g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        let parseTime = d3.timeParse("%Y%m%d");

        let x = d3.scaleTime().range([0, width]),
            y = d3.scaleLinear().range([height, 0]),
            z = d3.scaleOrdinal(d3.schemeCategory10);

        let line = d3.line()
            .curve(d3.curveBasis)
            .x(function(d) { return x(d.date); })
            .y(function(d) { return y(d.total); });





        // ----- PASS apiData RESPONSE OBJECT INTO HERE ------
        if (apiData) {
            console.log( apiData )

            x.domain(d3.extent( d3.map(apiData.roles, function(d) { return  parseTime(d.date)  }) ));

            y.domain([
                d3.min( apiData.roles, function(c) { return d3.min(c, function(d) { return d.total; }); }),
                d3.max( apiData.roles, function(c) { return d3.max(c, function(d) { return d.total; }); }),
            ]);

            z.domain( Object.keys(apiData) );

            g.append("text").attr("y",height/3).attr("x", width/3).text( ">>>" + apiData.roles.map( function(d) { d }).map(function (e) { return e } ).map(function (f) { return f } ) + "<<<" ) ;

        } else {
            g.append("text").attr("y",height/2).attr("x", width/2).text( "No API DATA!!!" );
        }


        // ----Everything below here is 'stock' Bostock D3 code

        g.append("g")
            .attr("class", "axis axis--x")
            .attr("transform", "translate(0,"+ height +")")
            .call(d3.axisBottom(x));

        g.append("g")
            .attr("class", "axis axis--y")
            .call(d3.axisLeft(y))
            .append("text")
            .attr("transform", "rotate(-90)")
            .attr("y", 6)
            .attr("dy", "0.71em")
            .attr("fill", "#000")
            .text("Total resource");

        let city = g.selectAll(".city")
            .data(apiData)
            .enter().append("g")
            .attr("class", "city");

        city.append("path")
            .attr("class", "line")
            .attr("d", function(d) { return line(d.values); })
            .style("stroke", function(d) { return z(d.id); });

        city.append("text")
            .datum(function(d) { return {id: d.key, value: d.values[d.values.length - 1]}; })
            .attr("transform", function(r) { return function(d) { return "translate(" + x(d.date) + "," + y(d.total) + ")"; } })
            .attr("x", 3)
            .attr("dy", "0.35em")
            .style("font", "10px sans-serif")
            .text(function(d) { return d.id; });


        // function type(d, _, columns) {
        //   d.date = parseTime(d.date);
        //   for (var i = 1, n = columns.length, c; i < n; ++i) d[c = columns[i]] = +d[c];
        //   return d;
        // }
    }


    updateD3() {
        this.props.animateFauxDOM(800)
        d3.select('text').text(this.props.title)
    }
}

MyD3ReactComponent.defaultProps = {
  myChart: 'loading'
};

MyD3ReactComponent.propTypes = {
  // title: PropTypes.string.isRequired,
  apiData: PropTypes.object.isRequired
}

const MyD3ReactComponentExport = withFauxDOM(MyD3ReactComponent);
export { MyD3ReactComponentExport }
沙尚克

设置域的问题是roles数组包含一个对象,您试图map查找d3.min和查找d3.max导致无效值的对象,因为这些函数仅适用于 ARRAYS。

例如,

y.domain([
     d3.min( apiData.roles, function(c) { return d3.min(c, function(d) { return d.total; }); }),
     d3.max( apiData.roles, function(c) { return d3.max(c, function(d) { return d.total; }); }),
]);

在上面的场景中,您apiData的变量c是一个不能应用min,的对象max

建议:使用尽可能多的 console.logs 并使用 Chrome 控制台或任何调试器添加断点。

为此,我首先按以下方式格式化数据:

// format data
var data = [];
apiData.roles.forEach(function(d) {
  var keys = Object.keys(d);
  keys.forEach(function(k) {
    data.push({key: k, values: d[k]});
  })
});

这是新格式化数据的外观:

[
{
"key": "AA",
"values": [
  {
    "date": "20150101",
    "total": 6
  },
  {
    "date": "20150201",
    "total": 14.5
  },
  {
    "date": "20150301",
    "total": 14.5
  }
]
},
{
"key": "AB",
"values": [
  {
    "date": "20150301",
    "total": 1.6
  },
  {
    "date": "20150401",
    "total": 1.6
  },
  {
    "date": "20150501",
    "total": 7.24
  }
]
}
]

使用这些数据,可以按如下方式创建图表:(我已经注释掉了文本部分:请使用格式化的数据来解决这个问题)

var apiData = {
    "roles": [
    {
        "AA": [
          {
          "date": "20150101",
          "total": 6.0
          },
          {
          "date": "20150201",
          "total": 14.5
          },
          {
          "date": "20150301",
          "total": 14.5
          }
        ],
        "AB": [
        {
        "date": "20150301",
        "total": 1.6
        },
        {
        "date": "20150401",
        "total": 1.6
        },
        {
        "date": "20150501",
        "total": 7.24
        }]
    }]
};

// format data
var data = [];
apiData.roles.forEach(function(d) {
	var keys = Object.keys(d);
  keys.forEach(function(k) {
    data.push({key: k, values: d[k]});
  })
});
//console.log(data);

        let svg = d3.select('div#chart').append('svg')
            .attr("width",960)
            .attr("height",500);

        let margin = {top: 20, right: 80, bottom: 30, left: 50},
            width = svg.attr("width") - margin.left - margin.right,
            height = svg.attr("height") - margin.top - margin.bottom,
            g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        let parseTime = d3.timeParse("%Y%m%d");

        let x = d3.scaleTime().range([0, width]),
            y = d3.scaleLinear().range([height, 0]),
            z = d3.scaleOrdinal(d3.schemeCategory10);

        let line = d3.line()
            .curve(d3.curveBasis)
            .x(function(d) { 
            	return x(parseTime(d.date)); 
            })
            .y(function(d) { return y(d.total); });





// ----- PASS apiData RESPONSE OBJECT INTO HERE ------
if (apiData) {
// console.log( apiData )
  
            x.domain([
                d3.min( data, function(c) { return d3.min(c.values, function(d) { return parseTime(d.date); }); }),
                d3.max( data, function(c) { return d3.max(c.values, function(d) { return parseTime(d.date); }); })
            ]);
           // console.log(x.domain());
            y.domain([
                d3.min( data, function(c) { return d3.min(c.values, function(d) { return +d.total; }); }),
                d3.max( data, function(c) { return d3.max(c.values, function(d) { return +d.total; }); }),
            ]);
//console.log(y.domain());

            z.domain( data.map(function(d) { return d.key; }) );

/*             g.append("text").attr("y",height/3).attr("x", width/3).text( ">>>" + apiData.roles.map( function(d) { d }).map(function (e) { return e } ).map(function (f) { return f } ) + "<<<" ) ; */
        // ----Everything below here is 'stock' Bostock D3 code

        g.append("g")
            .attr("class", "axis axis--x")
            .attr("transform", "translate(0,"+ height +")")
            .call(d3.axisBottom(x));

        g.append("g")
            .attr("class", "axis axis--y")
            .call(d3.axisLeft(y))
            .append("text")
            .attr("transform", "rotate(-90)")
            .attr("y", 6)
            .attr("dy", "0.71em")
            .attr("fill", "#000")
            .text("Total resource");

        let city = g.selectAll(".city")
            .data(data)
            .enter().append("g")
            .attr("class", "city");

        city.append("path")
            .attr("class", "line")
            .attr("d", function(d) { return line(d.values); })
            .style("stroke", function(d) { return z(d.key); });

/*         city.append("text")
            .datum(function(d) { return {id: d.key, value: d.values[d.values.length - 1]}; })
            .attr("transform", function(r) { 
              return function(d) { return "translate(" + x(d.date) + "," + y(d.total) + ")"; } })
            .attr("x", 3)
            .attr("dy", "0.35em")
            .style("font", "10px sans-serif")
            .text(function(d) { return d.key; }); */

        } else {
            g.append("text").attr("y",height/2).attr("x", width/2).text( "No API DATA!!!" );
        }
.city path {
  fill: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>

<div id="chart">

</div>

希望这可以帮助。:)

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何使用嵌套数组对象访问d3 json文件中的值

来自分类Dev

d3 - 数据 - 如何迭代嵌套对象

来自分类Dev

d3区域图,使用JSON对象

来自分类Dev

d3区域图,使用JSON对象

来自分类Dev

使用变量访问D3中的嵌套JSON键

来自分类Dev

使用Python创建D3嵌套JSON数据

来自分类Dev

如何使用D3处理高度嵌套的对象

来自分类Dev

如何在d3中使用对象打开json文件?

来自分类Dev

D3 stack()与嵌套对象

来自分类Dev

如何使用DataContractJsonSerializer解析嵌套的json对象?

来自分类Dev

如何使用DataContractJsonSerializer解析嵌套的json对象?

来自分类Dev

如何将hclust对象转换为D3的JSON?

来自分类Dev

如何获取json嵌套对象?

来自分类Dev

如何读取嵌套的json对象?

来自分类Dev

使用 d3 获取对象的值

来自分类Dev

使用PHP的嵌套对象json

来自分类Dev

如何使用json_decode访问嵌套的json对象

来自分类Dev

如何使用mysql本地json函数生成嵌套的json对象?

来自分类Dev

如何使用mysql本地json函数生成嵌套的json对象?

来自分类Dev

您如何使用D3访问对象数组?

来自分类Dev

如何使用d3动态更新嵌套列表?

来自分类Dev

使用D3绕过JSON

来自分类Dev

如何使用嵌套数组将JSON解析为对象

来自分类Dev

如何在Android中使用Retrofit解析嵌套的json对象

来自分类Dev

如何使用Python从Json文件的嵌套列表中提取对象?

来自分类Dev

如何使用jQuery从嵌套JSON对象获取值?

来自分类Dev

如何使用Gson从嵌套的JSON对象获取数据

来自分类Dev

如何使用jq从嵌套的JSON对象派生动态密钥?

来自分类Dev

如何使用xslt将嵌套的Json对象转换为xml