尝试制作带有条形图和差异线/值的动态 D3 图表

2023-12-14

我已询问以下有关创建显示差异值百分比和线条的条形图的帮助,以下是链接:

如何使用 D3.js 在条形图中创建带有值的百分比差异箭头线

我创建此线程是为了寻求帮助,使同一图表更加动态,以下是我的尝试:

  1. 以适合任何分辨率的方式使其动态化,即响应式(Div 的任何宽度和高度都可以渲染图表)
  2. 尝试进行反向差分计算。(目前是正向差分计算并显示正向箭头,但反向计算需要显示反向箭头)

(Edited: 例如:计算基本上将从最后一个柱开始,然后继续直到第一个柱。例如:(6453-7345)/7345 = -12% 和 (6453-5388)/6453 = -17%。)

enter image description here

  1. Trying to get the difference by first bar and last bar value i.e: enter image description here

下面也是代码:

var barData = [{
    "Time": "2019",
    "Value": 5388
    },
    {
    "Time": "2020",
    "Value": 6453
    },
    {
    "Time": "2021",
    "Value": 4345
    },
    {
    "Time": "2022",
    "Value": 7345
    },
    {
    "Time": "2023",
    "Value": 5345
    }];

    // Consider this width and Height are dynamic for div "graphID" because I am trying to responsive design
    const divWidth = 700,
    divHeight = 700;
    //Adding Margin to Viz Area
    var margin = {top: 30, right: 50, bottom: 0, left: 50},
    width = parseInt(divWidth,10) - margin.left - margin.right,
    height = parseInt(divHeight,10) - margin.top - margin.bottom;
    
    //To add svg in the visualization node i.e Dome node                    
    const svg = d3.select("#graphID").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
    //Adding x axis width i.e based on Viz Width                    
    const xScale = d3.scaleBand()
    .domain(barData.map(d => d.Time))
    .range([0, width]);


    const xAxis = d3.axisBottom(xScale);
    
    //Adding g attribute to svg for x axis
    svg.append('g')
    //.attr('transform', 'translate(20,170)')
    .attr("transform", "translate(10," + (height - 50) + ")") 
    .call(xAxis);
    
                        
    /*
    //To get the Max value from an json object
    const maxVal = barData.reduce((acc, shot) => acc = acc > shot.Value ? acc : shot.Value, 0);
    const valMax = Math.max.apply(barData, barData.map(function(o) { return o.Value; }));
    alert(valMax);
    
    const yScale = d3.scaleLinear()
    .domain([0, maxVal+(maxVal/2)])
    .range([150, 0]);
    */
    
    const yAxisMax = Math.max.apply(barData, barData.map(function(o) { return o.Value; }));
    
    const yScale = d3.scaleLinear()
    .domain([0, yAxisMax+(yAxisMax/2)])
    .range([height, 0]);

    const yAxis = d3.axisLeft(yScale).ticks(4);
    
    svg.append('g')
    //.attr('transform', 'translate(50,170)')
    .attr("transform", "translate(10,-50)") 
    //.attr("transform", "translate(20," + (height - 50) + ")") 
    .call(yAxis);

    const bars = svg.selectAll('g.bar')
    .data(barData)
    .enter()
    .append('g')
    .classed('bar', true)
    .attr('transform', d => `translate(${xScale(d.Time) + 50 + xScale.bandwidth() / 20}, 170)`)

    bars.append('rect')
    .attr('x', -10)
    .attr('width', 40)
    .attr('y', d =>  -height + yScale(d.Value))
    .attr('height', d => yScale(d.Value) )
    .style('fill', 'blue')

    bars.append('text')
    .text(d => d.Value)
    .attr('text-anchor', 'middle')
    .attr('y', d => -(height - 55) + yScale(d.Value))

    bars.filter((d, i) => i < barData.length - 1)
    .append('path')
    .attr('d', (d, i) => `M 5,${-170 + yScale(d.Value)} V ${-210 + yScale(d.Value)} H ${xScale.bandwidth() - 5} V ${-180 + yScale(barData[i + 1].Value)}`)
    .style('stroke', 'gray')
    .style('fill', 'none')
    .attr('marker-end', 'url(#arrowhead)')

    bars.filter((d, i) => i < barData.length - 1)
    .append('rect')
    .attr('x', 15)
    .attr('y', d => -220 + yScale(d.Value))
    .attr('width', xScale.bandwidth() - 30)
    .attr('height', 20)
    .attr('rx', 10)
    .style('fill', 'white')
    .style('stroke', 'gray');

    bars.filter((d, i) => i < barData.length - 1)
    .append('text')
    .text((d, i) => `${barData[i + 1].Value > d.Value ? '+' : '-'}${Math.round((barData[i + 1].Value / d.Value * 100) - 100)}%`)
    .attr('x', xScale.bandwidth() / 2)
    .attr('y', d => -207 + yScale(d.Value))
    .attr('text-anchor', 'middle')
    .style('fill', 'black');
#graphID
{
    width:500px;
    height:700px
}
text {
  font-size: 12px;
  font-family: "Ubuntu";
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="graphID" width=500 height=700>

</div>

这是响应式调整大小的解决方案:

  1. 获取父容器的尺寸:
  const container = d3.select('#graph');
  const divWidth = parseInt(container.style('width'));
  const divHeight = parseInt(container.style('height'));
  1. 使用 DIV 尺寸创建 SVG:
const svg = container.append("svg")
 .attr("width", divWidth)
 .attr("height", divHeight);
  1. 使用边距计算图表大小:
const margin = {top: 30, right: 50, bottom: 50, left: 50};
const width = divWidth - margin.left - margin.right;
const height = divHeight - margin.top - margin.bottom;
  1. 添加家长<g>并使用边距定位它。所有其他元素应放置在:
const svgG = svg.append("g")
   .attr("transform", `translate(${margin.left},${margin.top})`);
    var barData = [{
        "Time": "2019",
        "Value": 5388
        },
        {
        "Time": "2020",
        "Value": 6453
        },
        {
        "Time": "2021",
        "Value": 4345
        },
        {
        "Time": "2022",
        "Value": 7345
        },
        {
        "Time": "2023",
        "Value": 5345
        }];

    const container = d3.select('#graph');
  const divWidth = parseInt(container.style('width'));
    const divHeight = parseInt(container.style('height'));

// Consider this width and Height are dynamic for div "graphID" because I am trying to responsive design
    const margin = {top: 30, right: 50, bottom: 50, left: 50};
  const width = divWidth - margin.left - margin.right;
  const height = divHeight - margin.top - margin.bottom;
        
        //To add svg in the visualization node i.e Dome node                    
 const svg = container.append("svg")
   .attr("width", divWidth)
   .attr("height", divHeight);
      
 const svgG = svg.append("g")
   .attr("transform", `translate(${margin.left},${margin.top})`);
        
const xScale = d3.scaleBand()
  .domain(barData.map(d => d.Time))
  .range([0, width]);

const xAxis = d3.axisBottom(xScale);
        
//Adding g attribute to svg for x axis
svgG.append('g')
    .attr("transform", `translate(0,${height})`) 
    .call(xAxis);
        
const yAxisMax = barData.reduce((max, item) => Math.max(max, item.Value), 0) * 1.5;
        
const yScale = d3.scaleLinear()
    .domain([0, yAxisMax])
    .range([height, 0]);

const yAxis = d3.axisLeft(yScale).ticks(4);
        
svgG.append('g')
    .call(yAxis);

const bars = svgG.selectAll('g.bar')
    .data(barData)
    .enter()
    .append('g')
  .classed('bar', true)
  .attr('transform', d => `translate(${xScale(d.Time) + xScale.bandwidth() / 2}, 0)`)

bars.append('rect')
    .attr('x', -20)
    .attr('width', 40)
    .attr('y', d =>  yScale(d.Value))
    .attr('height', d => height - yScale(d.Value) )
    .style('fill', 'blue')

bars.append('text')
    .text(d => d.Value)
    .attr('text-anchor', 'middle')
    .attr('y', d => yScale(d.Value))
  .attr('dy', -5)

bars.filter((d, i) => i < barData.length - 1)
    .append('path')
    .attr('d', (d, i) => `M 5,${yScale(d.Value) - 20} V ${Math.min(yScale(d.Value), yScale(barData[i + 1].Value)) - 60} H ${xScale.bandwidth() - 5} V ${yScale(barData[i + 1].Value) - 20}`)
        .style('stroke', 'gray')
        .style('fill', 'none')
        .attr('marker-end', 'url(#arrowhead)')

bars.filter((d, i) => i < barData.length - 1)
  .append('rect')
  .attr('x', 15)
  .attr('y', (d, i) => Math.min(yScale(d.Value), yScale(barData[i + 1].Value)) - 70)
  .attr('width', xScale.bandwidth() - 30)
  .attr('height', 20)
  .attr('rx', 10)
  .style('fill', 'white')
  .style('stroke', 'gray');

bars.filter((d, i) => i < barData.length - 1)
    .append('text')
    .text((d, i) => `${barData[i + 1].Value > d.Value ? '+' : '-'}${Math.round((barData[i + 1].Value / d.Value * 100) - 100)}%`)
  .attr('x', xScale.bandwidth() / 2)
  .attr('y', (d, i) => Math.min(yScale(d.Value), yScale(barData[i + 1].Value)) - 56)
  .attr('text-anchor', 'middle')
  .style('fill', 'black');
#graph
{
  width:500px;
  height:700px
 }
 
 text {
   font-size: 12px;
   font-family: "Ubuntu";
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="graph">
</div>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

尝试制作带有条形图和差异线/值的动态 D3 图表 的相关文章

随机推荐

  • 最佳实践 - 只下载您需要的 CSS,还是使用缩小过程?

    在改善的背景下overall站点性能 下载和渲染速度 以下两个最佳实践之间似乎存在矛盾 仅降低正在查看的页面所需的 CSS 因为CSS规则过多导致渲染速度慢 始终缩小 CSS 并将其合并到一个文件中 因为更多的请求意味着更慢的页面加载 现在
  • 如何在 Selenium 中获得“nth-of-type”

    我正在使用 Selenium Webdriver 检查此特定段落的文本 此处以蓝色突出显示的段落 但我如何 查询 该段落呢 这就是我正在尝试的 不起作用 def test intro text self Test that intro te
  • 设置 jwplayer youtube 视频播放质量

    我正在使用 jw 播放器播放 youtube 视频 但我需要视频开始以高清 720p 播放 我使用以下代码 div div 但我收到以下错误 回调事件处
  • 基于身份列的 JPA 派生列值

    JPA 2 0 Hibernate 4 2 4 Final Spring 3 2 8 Release Mysql 5 6 对于具有自动生成主键的托管实体 E 例如 Id GeneratedValue private int id Colum
  • SAXParser '&' 连接问题

    我目前正在将 SAXParser 与 SAXParserFactory 一起使用 并且遇到了字符串在 符号处被截断的问题 例如 国家创造了我们的世界及其中的一切 变成 其中的一切 显然 我不希望这种情况发生 在 xml 输入中 字符被正确转
  • 这个类应该使用数据锁定进行多线程吗?

    我有一个包含一些数据的类 并且有很多线程使用它 class MyClass static Dictionary
  • 使用“VNImageHomographAlignmentObservation”类合并图像

    我正在尝试使用合并两个图像VNImageHomographicAlignmentObservation 我目前得到的 3d 矩阵如下所示 simd float3x3 0 99229 0 00451023 4 32607e 07 0 0043
  • 简单列表到数据框

    假设我有一个列表 red red 1 red blue 3 red yellow 2 blue red 3 blue blue 1 blue yellow 4 yellow red 2 yellow blue 4 yellow yellow
  • jq 中包含“@”和“-”的转义字段名称? [复制]

    这个问题在这里已经有答案了 输入 JSON abc def ghi value1 xyz value2 我正在努力获得领域的价值 def ghi 0 echo abc def ghi value1 xyz value2 jq abc xyz
  • 如何制作一个从服务器读取电子邮件的PHP脚本?

    当我用户发送电子邮件至 电子邮件受保护 php 脚本读取电子邮件的信息并自动重播给用户 编辑 当有人向我发送电子邮件时 有什么方法可以 电子邮件受保护 将调用一个脚本 这比每 5 秒使用 cron 作业更好 Cheer 正如已经建议的 检查
  • 修复基于光盘的缓存大小的最佳方法是什么?android-volley

    1 android volley 中基于磁盘的缓存的默认实现分配的总内存为 5MB 2 但是我正在开发的应用程序包含很多图像 所以我想增加基于磁盘的缓存分配的内存大小 3 所以我想增加缓存的大小 我可以通过更改 Diskbasedcache
  • 使用 Jersey 的 Java Web 服务

    我们尝试通过以下链接使用 Jersey 和 Tomcat 在 Java 中创建示例 Web 服务 helloworld http www vogella de articles REST article html http www ibm
  • 这里应该使用表值参数吗?

    我有以下查询 UPDATE students SET IsDeleted 1 WHERE StudentId IN SELECT StudentId FROM Class where PassId IN SELECT Id FROM Cla
  • AS3:setSelection 向上箭头覆盖

    当按下向上箭头时 我想关注 TextField 的末尾 我在用着 txt setSelection txt text length txt text length 这对于除向上箭头之外的任何键都非常有效 我相信当焦点处于文本字段的开头时 向
  • C++ 中的 MATLAB 函数 [关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 有谁知道我们可以获得的资源FREEMATLAB 函数的 C 库 例如 线性代数问题可以使用 LAPACK 和 BLAS 来解决 另外 NET 项目中的 MATLAB 也是不可能的 我
  • Node.js 自签名证书在我的浏览器中仍然显示为“不受信任”

    我正在运行 Node js 服务器 并且尝试在本地托管该服务器并且不会收到任何 SSL 错误 这是我创建证书的过程 我在 Visual Studio Code 中打开终端并输入以下内容 openssl req nodes new x509
  • 将正向前瞻 (?=regex) 与 re2 一起使用

    因为我有点新re2 我试图弄清楚如何使用正向前瞻 regex 像 JS C 或任何 PCRE 风格Go 这是我正在寻找的一些示例 JS foo bar baz match s S baz Python re match s S baz fo
  • 在 C++ 中使用正则表达式对字符串进行标记并保留分隔符

    我想修改给定的正则表达式以生成以下匹配列表 我很难用语言描述这个问题 我想使用正则表达式来匹配一组 标记 具体我想要 要匹配 任何不包含这些字符的字符串都应该是匹配的 我遇到的问题是区分一根管道和两根管道 我怎样才能产生所需的匹配 非常感谢
  • 将函数应用于我的数据框中的所有列

    我无法将自定义函数应用到dataframe df pd DataFrame a related 1 related 0 related 1 b request 1 request 0 request 1 c offer 1 offer 0
  • 尝试制作带有条形图和差异线/值的动态 D3 图表

    我已询问以下有关创建显示差异值百分比和线条的条形图的帮助 以下是链接 如何使用 D3 js 在条形图中创建带有值的百分比差异箭头线 我创建此线程是为了寻求帮助 使同一图表更加动态 以下是我的尝试 以适合任何分辨率的方式使其动态化 即响应式