简体   繁体   中英

Scatter plot using d3 with React

I am trying to create a scatter plot using d3 with React. There aren't many examples available but I foundthis useful. So my code is given below:

class Axis extends React.Component {
    constructor(props) {
        super(props);
    }

    componentDidUpdate() {
        this.renderAxis();
    }

    componentDidMount() {
        this.renderAxis();
    }

    renderAxis() {
        const node = ReactDOM.findDOMNode(this);
        d3.select(node).call(this.props.axis);
    }

    render() {
        const translate = 'translate(0,'+(this.props.h)+')';

        return (
            <g className='axis' transform={this.props.axisType == 'x' ? translate : "" }>
            </g>
        );
    }
}


Axis.propTypes = {
    h: React.PropTypes.number,
    axis: React.PropTypes.func,
    axisType: React.PropTypes.oneOf(['x', 'y'])
};

class Points extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {

        const _self = this;
        const circles = _self.props.data.map((d, i) => {
            return (
                <circle className="dot" r="3.5" cx={_self.props.x(d)} cy={_self.props.y(d)} key={i} fill="red"/>
            );
        });
        return (
            <g>{circles}</g>
        );
    }
}

Points.propTypes = {
    data: React.PropTypes.array,
    x: React.PropTypes.func,
    y: React.PropTypes.func
}

export default class PlotBlock extends React.Component {
  constructor(props) {
        super(props);
    this.state = {
        csvData: ''
    };
  }

componentWillMount() {
    let inputData;

    inputData = [{"Name":"A1_P1","Category":"A01","Score 1":"2.3","Score 2":"2.4","Score 3":"4.1","Average score":"2.4"},{"Name":"A2_P1","Category":"A02","Score 1":"1.4","Score 2":"1.5","Score 3":"2.4","Average score":"1.5"},{"Name":"A3_P1","Category":"A03","Score 1":"0.9","Score 2":"0.9","Score 3":"0.9","Average score":"0.9"},{"Name":"A4_P1","Category":"B01","Score 1":"1.5","Score 2":"1.5","Score 3":"1","Average score":"1.5"},{"Name":"A5_P1","Category":"B02","Score 1":"1.2","Score 2":"1.2","Score 3":"1.4","Average score":"1.2"},{"Name":"A6_P1","Category":"B03","Score 1":"1","Score 2":"1","Score 3":"1.1","Average score":"1"},{"Name":"A7_P1","Category":"C01","Score 1":"1.6","Score 2":"1.2","Score 3":"1","Average score":"1.2"},{"Name":"A8_P1","Category":"C02","Score 1":"1.2","Score 2":"1.2","Score 3":"0.9","Average score":"1.2"},{"Name":"A9_P1","Category":"C03","Score 1":"1.1","Score 2":"1.1","Score 3":"1","Average score":"1.1"},{"Name":"A10_P1","Category":"D01","Score 1":"1.5","Score 2":"1.6","Score 3":"1.1","Average score":"1.5"}];

    this.setState({ csvData: inputData });

}

  render() {
    const margin = {top: 20, right: 20, bottom: 30, left: 50};
    const width = 720 - margin.left - margin.right;
    const height = 200 - margin.top - margin.bottom;

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

    const x = (d) => d['Category'];
    const xScale = d3.scalePoint()
                     .range([0, width]);
    const xMap = (d) => {
      return xScale(x(d));
    };
    const xAxis = d3.axisBottom(xScale);

    const y = (d) => d['Score'];
    const yScale = d3.scaleLinear()
                     .range([height, 0]);
    const yMap = (d) => {;
      return yScale(y(d));
    };
    const yAxis = d3.axisLeft(yScale);

    const svgContainerWidth = width + margin.left + margin.right;
    const svgContainerHeight = height + margin.top + margin.bottom + 200;
    const innerContainer = 'translate(' + margin.left + ',' + margin.top + ')';


    if (this.state.csvData) {
        return (
            <div className='plot-block'>
                <svg width={svgContainerWidth} height={svgContainerHeight}>
                    <g transform={innerContainer}>
                      <Axis h={height} axis={xAxis} axisType="x" />
                      <Axis h={height} axis={yAxis} axisType="y" />
                      <Points data={this.state.csvData} x={xMap} y={yMap} />
                    </g>
                </svg>
            </div>
        );
    }
    return null;
  }
}

The graph looks like this:

在此处输入图片说明

The biggest problem is that the 'cx' attribute for the dots don't appear at all, and the 'cy' values also seem to be wrong. I know because I plotted the graph successfully using only d3 and. Specially, when calling xMap and yMap the values are all wrong even though the function and input parameters seem to be the same as when plotting using only d3. I am really confused and there are no real good examples of React + d3 integration. Please help.

I'm not a React user, but regarding the D3 part of your code, I believe it's missing the domain for both scales.

They should be:

const yScale = d3.scaleLinear()
    .domain([0, d3.max(data, y)])
    .range([height, 0]);

const xScale = d3.scalePoint()
    .domain(data.map((d) => d["Category"]))
    .range([0, width]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM