gpt4 book ai didi

javascript - 如何使用 D3 使用 JSON 数据创建折线图

转载 作者:行者123 更新时间:2023-12-04 11:50:02 28 4
gpt4 key购买 nike

我正在使用 D3.js 和 react-hooks 来创建图表,所以我尝试创建一个 Line通过四处搜索得到一张图表。

  • 但我正在使用的是样本数据,在我的例子中,我有 JSON 数据。
  • 我也使用 resize-observer-polyfill 使图表具有响应性。这个图书馆。
  • 现在我正在努力用 JSON 数据来实现它,用动态数据来呈现它。

  • 我做了什么
    const svgRef = useRef();
    const wrapperRef = useRef();
    const dimensions = useResizeObserver(wrapperRef); // for responsive

    // will be called initially and on every data change
    useEffect(() => {
    const svg = select(svgRef.current);
    const { width, height } =
    dimensions || wrapperRef.current.getBoundingClientRect();

    // scales + line generator
    const xScale = scaleLinear()
    .domain([0, data.length - 1]) // here I need to pass the data
    .range([0, width]);

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

    const lineGenerator = line()
    .x((d, index) => xScale(index))
    .y((d) => yScale(d))
    .curve(curveCardinal);

    // render the line
    svg
    .selectAll('.myLine')
    .data([data])
    .join('path')
    .attr('class', 'myLine')
    .attr('stroke', 'black')
    .attr('fill', 'none')
    .attr('d', lineGenerator);

    svg
    .selectAll('.myDot')
    .data(data)
    .join('circle')
    .attr('class', 'myDot')
    .attr('stroke', 'black')
    .attr('r', (value, index) => 4)
    .attr('fill', (value, index) => 'red')
    .attr('cx', (value, index) => xScale(index))
    .attr('cy', yScale);

    // axes
    const xAxis = axisBottom(xScale);
    svg
    .select('.x-axis')
    .attr('transform', `translate(0, ${height})`)
    .call(xAxis);

    const yAxis = axisLeft(yScale);
    svg.select('.y-axis').call(yAxis);
    }, [data, dimensions]);

    <React.Fragment>
    <div ref={wrapperRef} style={{ marginBottom: '2rem' }}>
    <svg ref={svgRef}>
    <g className="x-axis" />
    <g className="y-axis" />
    </svg>
    </div>
    </React.Fragment>
    这里我无法传递数据,我的数据在下面
    [
    { anno: 2014, consumo: 300, color: "#ff99e6" },
    { anno: 2015, consumo: 290, color: "blue" },
    { anno: 2016, consumo: 295, color: "green" },
    { anno: 2017, consumo: 287, color: "yellow" },
    { anno: 2018, consumo: 282, color: "red" },
    { anno: 2019, consumo: 195, color: "white" }
    ]
    在我的数据中,每个数据都有颜色,我想在生成的每个点中显示。
    working code sandbox of line chart
    同样,我尝试做条形图,它工作正常
    我对标签进行了一些动态渲染,当我们调整窗口大小时,标签会自动调整。
    Here is the full working bar chart what I am trying to implement to line chart
    我还评论了我在做什么。
    编辑/更新
    我一直在关注@MGO 的回答,它帮助了我很多,但我仍然面临对齐标签并将颜色填充为点的问题。
    as you can see the labels are overlapping to each other
    实际上很明显它会因为文本大小而重叠,但只是为了克服我在下面的代码中使用的条形图中
     const tickWidth = 40;
    const width = xScaleLabels.range()[1];
    const tickN = Math.floor(width / tickWidth);
    const keepEveryNth = Math.ceil(xScaleLabels.domain().length / tickN);

    const xScaleLabelDomain = xScaleLabels
    .domain()
    .filter((_, i) => i % keepEveryNth === 0);
    xScaleLabels.domain(xScaleLabelDomain);
    它所做的是当设备尺寸较小时,它将过滤一些标签并且不会显示标签。
    而且我正在使用下面的代码来给颜色
    .attr("fill", ({ color }) => color) 
    但是它没有采用任何颜色,而是默认采用黑色。
    我有数据显示为标签 July.9.2021 11:18:28但我只想显示时间,所以我在条形图代码中所做的如下
    const xScaleLabels = scaleBand()
    .domain(
    data.map(
    ({ sensorValueAddedTime }) => sensorValueAddedTime.split(' ')[2] // this I am using to show only time
    )
    )
    .range([0, dimensions.width])
    .padding(padding);
    同样,我正在尝试使用折线图,以一种简单的方式,我不想将其更改为任何时间。
    这是第二个数据,所以基本上我得到的答案只适用于第一个数据而不是第二个数据,如果数据以我想要显示的任何这些格式出现,我希望它是动态的。 sensorValueAddedTime我想在 x 轴上显示 sensorValue在 y 轴上
    我已经添加了我的条形图完整工作代码,我想对折线图做同样的事情。
        [
    {
    sensorValue: 32,
    sensorValueAddedTime: "July.9.2021 10:56:22",
    color_code: null,
    condition: null,
    __typename: "sensorData"
    },
    {
    sensorValue: 32,
    sensorValueAddedTime: "July.9.2021 10:56:23",
    color_code: null,
    condition: null,
    __typename: "sensorData"
    },
    {
    sensorValue: 35,
    sensorValueAddedTime: "July.9.2021 11:17:51",
    color_code: null,
    condition: null,
    __typename: "sensorData"
    },
    {
    sensorValue: 35,
    sensorValueAddedTime: "July.9.2021 11:17:52",
    color_code: null,
    condition: null,
    __typename: "sensorData"
    },
    {
    sensorValue: 36,
    sensorValueAddedTime: "July.9.2021 11:18:08",
    color_code: null,
    condition: null,
    __typename: "sensorData"
    },
    {
    sensorValue: 36,
    sensorValueAddedTime: "July.9.2021 11:18:09",
    color_code: null,
    condition: null,
    __typename: "sensorData"
    },
    {
    sensorValue: 38,
    sensorValueAddedTime: "July.9.2021 11:18:27",
    condition: null,
    color_code: null,
    __typename: "sensorData"
    },
    {
    sensorValue: 38,
    sensorValueAddedTime: "July.9.2021 11:18:28",
    condition: null,
    color_code: null,
    __typename: "sensorData"
    }
    ]

    最佳答案

    在 Muri 的 D3 with React Hooks video series 的原始示例中data是一个平面一维数组:[10, 25, 30, 40, 25, 60] .
    在您提供的新数组 (data1) 中,我们要求 D3 基于对象数组呈现图表。所以当我们通过 data1作为我们图表函数的一个支柱,我们需要做更多的工作来访问我们的对象数组中的值。
    我们需要将数据值缩放到适当的范围内。原始示例通过数组中的索引查找值。我们将需要访问 data1 中包含的对象中的值。基于这些对象的键的数组。像这样,创建我们的音阶:

    const yScale = scaleLinear()
    .domain([0, max(data, (d) => d.sensorValue)])
    .range([height, 0]);

    // scale the values of sensorValueAddedTime into the range for our x axis values
    // since it's a date you'll need to convert the strings to Date objects:

    const xScale = scaleTime()
    .domain([
    new Date(min(data, (d) => d.sensorValueAddedTime)),
    new Date(max(data, (d) => d.sensorValueAddedTime))
    ])
    .range([0, width]);

    就像这样,在我们的 lineGenerator功能:
    const lineGenerator = line()
    .x((d) => xScale(new Date(d.sensorValueAddedTime))
    .y((d) => yScale(d.sensorValue));
    您会在上面注意到,如果我们要使用 scaleTime() ,我们必须转换 sensorValueAddedTime转换为 D3 可以理解的值——现在你的对象的字符串中有一个额外的空格,但是如果你去掉那个空格 you can convert to a Date object and use d3.scaleTime() .
    There's an updated, working Sandbox that's rendering this data to a line chart with additional comments here.
    更新:OP 要求绘制一组不同的数据,并要求这些点“按该顺序出现”。
    There's a different working Sandbox rendering this different set of data to a line chart correctly here.
    这似乎是您所要求的——“条形图的折线图版本”可能不会产生您所追求的。只是通过它来说话:
    如果您使用 xScale 上每个对象的索引位置,如下所示:
    const xScale = scaleLinear()
    .domain([0, data.length - 1])
    .range([0, width]);
    这将产生一个非常无聊的图表——因为你说“在每个代表数组索引的整数上放一个点”。换句话说,1 处、2 处、3 处的点,以此类推。
    对于这个图表,我们应该在数据中选择有意义的值——比如 data1.anno - 并使用它们进行交流。
    例如:
    根据数组的索引位置将值缩放到范围内,并根据它们的索引位置绘制它们,如下所示:
    const xScale = scaleLinear()
    .domain([0, data.length - 1])
    .range([0, width]);


    ....chart code....

    .attr("cx", (value, index) => xScale(index))
    产生这个情节:
    plot of points by index position in array
    解决方案
    将数据的值缩放到范围内并根据它们的值绘制点。我们可以使用 d3's extent method , 像这样:
    const xScale = scaleLinear()
    .domain(extent(data, (d) => d.anno))
    .range([0, width]);

    const yScale = scaleLinear()
    .domain([0, max(data, (d) => d.consumo)])
    .range([height, 0]);

    ....chart code...

    .attr("cx", (value) => xScale(value.anno))
    .attr("cy", (value) => yScale(value.consumo));
    产生这个情节:
    enter image description here data1.anno显然是一年。将年份解析为日期对象的选项是一个不错的选择。 var parse = d3.timeParse("%Y") ,然后使用它来设置您的时间尺度的域: .domain([parse(minDate), parse(maxDate)]) , as shown here .
    否则,如果您想在 x 轴上保留该值而不将其视为 Date 对象,您可以使用 Javascript 的 toFixed()删除小数位的方法,使用 d3.format 删除逗号分隔符并更改显示为 axis.ticks() 的刻度数.
    这产生了这个图表:
    enter image description here
    要使用这些点生成一条线,请使用数据中的值,而不是索引。
    const lineGenerator = line()
    // .x((d, index) => xScale(index)) // old
    // .y((d) => yScale(d)) // old
    .x((d) => xScale(d.anno)) // new
    .y((d) => yScale(d.consumo)) // new
    .curve(curveCardinal);
    这产生了这个图表:
    enter image description here
    最后,如果您的目标是将每个对象中的颜色值分配给一个点,请访问这些值并将它们的值分配给填充,如下所示:
    .attr("fill", (value) => value.color)

    这产生了这个图表:
    enter image description here
    Here's the working sandbox.
    希望这可以帮助! ✌️

    关于javascript - 如何使用 D3 使用 JSON 数据创建折线图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68342421/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com