wps图表中如何插入甘特图_如何通过使用D3可视化数据集来构建类似甘特图的图表...

本文介绍了如何使用D3.js从分钟级数据构建类似甘特图的可视化,强调正确组织数据集的重要性。作者展示了创建数据集、定义x轴、放置项目和着色的过程,并提到了创建可重用图表的技巧。
摘要由CSDN通过智能技术生成

wps图表中如何插入甘特图

by Déborah Mesquita

由DéborahMesquita

如何通过使用D3可视化数据集来构建类似甘特图的图表 (How to build a Gantt-like chart by using D3 to visualize a dataset)

When you finish learning about the basics of D3.js, usually the next step is to build visualizations with your dataset. Because of how D3 works, the way we organize the dataset can make our lives really easy or really hard.

当您学习完D3.js的基础知识后,通常下一步就是使用数据集构建可视化。 由于D3的工作方式,我们组织数据集的方式可以使我们的生活变得轻松或艰难。

In this article we will discuss different aspects of this building process. To illustrate these aspects, we will build a visualization that is similar to a Gantt chart.

在本文中,我们将讨论此构建过程的不同方面。 为了说明这些方面,我们将建立类似于甘特图的可视化效果。

The most important lesson I learned is that you need to build a dataset where each datapoint equals a data unity of your graph. Let’s dive into our case study to see how this works.

我学到的最重要的一课是, 您需要构建一个数据集,其中每个数据点都等于图形的数据单位 。 让我们深入研究案例研究以了解其工作原理。

The goal is to build a Gantt-like chart similar to the one below:

目标是建立类似于以下甘特图的图表:

As you can see, it’s not a Gantt chart because the tasks start and finish on the same day.

如您所见,它不是甘特图,因为任务在同一天开始和结束。

创建数据集 (Creating the dataset)

I extracted the data from minutes. For each text file, I received information about the projects and their statuses from meetings. At first, I structured my data like this:

我从几分钟提取数据。 对于每个文本文件,我从会议中收到有关项目及其状态的信息。 首先,我将数据结构如下:

{    "meetings": [{            "label": "1st Meeting",            "date": "09/03/2017",            "projects_presented": [],            "projects_approved": ["002/2017"],            "projects_voting_round_1": ["005/2017"],            "projects_voting_round_2": ["003/2017", "004/2017"]        },        {            "label": "2nd Meeting",            "date_start": "10/03/2017",            "projects_presented": ["006/2017"],            "projects_approved": ["003/2017", "004/2017"],            "projects_voting_round_1": [],            "projects_voting_round_2": ["005/2017"]        }    ]}

Let’s take a closer look at the data.

让我们仔细看看数据。

Each project has 4 statuses: presented, voting round 1, voting round 2 and approved. In each meeting, the status for the projects can or can not change. I structured the data by grouping them by meetings. This grouping gave us a lot of problems when we built the visualization. This was because we needed to pass data to nodes with D3. After I saw the Gantt chart that Jess Peter built here, I realized I needed to change my data.

每个项目都有4个状态:已presentedvoting round 1 voting round 2approved 。 在每次会议中,项目的状态都可以更改,也可以不更改。 我通过按会议对数据进行分组来构造数据。 建立可视化时,这种分组给我们带来了很多问题。 这是因为我们需要将数据传递到具有D3的节点。 看到Jess Peter 在这里建立的甘特图后,我意识到我需要更改数据。

What was the minimum information I wanted to display? What was the minimum node? Looking at the picture, it is the information of the project. So I changed the structure of the data to the following:

我想显示的最少信息是什么? 最小节点是多少? 看图片,这是项目的信息。 因此,我将数据的结构更改为以下内容:

{  "projects": [                  {                    "meeting": "1st Meeting",                    "type": "project",                    "date": "09/03/2017",                    "label": "Project 002/2017",                    "status": "approved"                  },                  {                    "meeting": "1st Meeting",                    "type": "project",                    "date": "09/03/2017",                    "label": "Project 005/2017",                    "status": "voting_round_1"                  },                  {                    "meeting": "1st Meeting",                    "type": "project",                    "date": "09/03/2017",                    "label": "Project 003/2017",                    "status": "voting_round_2"                  },                  {                    "meeting": "1st Meeting",                    "type": "project",                    "date": "09/03/2017",                    "label": "Project 004/2017",                    "status": "voting_round_2"                  }               ]}

And everything worked better after that. It's funny how the frustration disappeared after this simple change.

在那之后一切都变好了。 有趣的是,在进行了简单的更改后,挫折感消失了。

创建可视化 (Creating the visualization)

Now that we have the dataset, let’s start building the visualization.

现在我们有了数据集,让我们开始构建可视化。

创建x轴 (Creating the x-axis)

Each date should be displayed in the x-axis. To do that, define d3.timeScale() :

每个日期都应显示在x轴上。 为此,定义d3.timeScale()

var timeScale = d3.scaleTime()                .domain(d3.extent(dataset, d => dateFormat(d.date)))                .range([0, 500]);

The minimum and maximum values are given in the arrayd3.extent().

最小值和最大值在数组d3.extent()

Now that you have timeScale , you can call the axis.

现在有了timeScale ,您可以调用轴了。

var xAxis = d3.axisBottom()                .scale(timeScale)                .ticks(d3.timeMonth)                .tickSize(250, 0, 0)                .tickSizeOuter(0);

The ticks should be 250px long. You don’t want the outer tick. The code to display the axis is:

刻度线应为250px长。 您不需要外部刻度线。 显示轴的代码是:

d3.json("projects.json", function(error, data) {            chart(data.projects);});
function chart(data) {    var dateFormat = d3.timeParse("%d/%m/%Y");
var timeScale = d3.scaleTime()                   .domain(d3.extent(data, d => dateFormat(d.date)))                   .range([0, 500]);
var xAxis = d3.axisBottom()                  .scale(timeScale)                  .tickSize(250, 0, 0)                  .tickSizeOuter(0);
var grid = d3.select("svg").append('g').call(xAxis);}

If you plot this, you can see that there are many ticks. In fact, there are ticks for each day of the month. We want to display only the days that had meetings. To do that, we will set the tick values explicitly:

如果绘制此图,则可以看到有许多刻度线。 实际上,每月的每一天都有刻度。 我们只想显示开会的日期。 为此,我们将显式设置刻度值:

let dataByDates = d3.nest().key(d => d.date).entries(data);let tickValues = dataByDates.map(d => dateFormat(d.key));
var xAxis = d3.axisBottom()                .scale(timeScale)                .tickValues(tickValues)                .tickSize(250, 0, 0)                .tickSizeOuter(0);

Using d3.nest() you can group all the projects by date (see how handy it is to structure the data by projects?), and then get all the dates and pass it to the axis.

使用d3.nest()您可以按日期对所有项目进行分组(请参见按项目对数据进行结构化有多方便?),然后获取所有日期并将其传递给轴。

放置项目 (Placing the projects)

We need to place the projects along the y-axis, so let’s define a new scale:

我们需要沿y轴放置项目,所以让我们定义一个新的比例尺:

yScale = d3.scaleLinear().domain([0, data.length]).range([0, 250]);

The domain is the number of projects. The range is the size of each tick. Now we can place the rectangles:

域是项目数。 范围是每个刻度的大小。 现在我们可以放置矩形:

var projects = d3.select("svg")                   .append('g')                   .selectAll("this_is_empty")                   .data(data)                   .enter();
var innerRects = projects.append("rect")              .attr("rx", 3)              .attr("ry", 3)              .attr("x", (d,i) => timeScale(dateFormat(d.date)))              .attr("y", (d,i) => yScale(i))              .attr("width", 200)              .attr("height", 30)              .attr("stroke", "none")              .attr("fill", "lightblue");

selectAll(), data(), enter() and append() always get tricky. To use the enter() method (in order to create a new node from a datapoint), we need a selection. That’s why we need selectAll("this_is_empty)", even if we don’t have anyrect yet. I've used this name to clarify that we only need the empty selection. In other words, we use selectAll("this_is_empty)" to get an empty selection we can work on.

selectAll()data()enter()append()总是很棘手。 要使用enter()方法(为了从数据点创建新节点),我们需要进行选择。 这就是为什么我们需要selectAll("this_is_empty)" ,即使我们还没有任何rect 。 我用这个名字来说明我们只需要空选择。 换句话说,我们使用selectAll("this_is_empty)"来获得我们可以处理的空选择。

The variable projects has empty selections bounded to data, so we can use it to draw the projects in innerRects.

变量projects具有绑定到数据的空选择,因此我们可以使用它在innerRects绘制项目。

Now you can also add a label for each project:

现在,您还可以为每个项目添加标签:

var rectText = projects.append("text")                .text(d => d.label)                .attr("x", d => timeScale(dateFormat(d.date)) + 100)                .attr("y", (d,i) => yScale(i) + 20)                .attr("font-size", 11)                .attr("text-anchor", "middle")                .attr("text-height", 30)                .attr("fill", "#fff");
为每个项目着色 (Coloring each project)

We want the color of each rectangle to reflect the status of each project. To do that, let’s create another scale:

我们希望每个矩形的颜色反映每个项目的状态。 为此,让我们创建另一个音阶:

let dataByCategories = d3.nest().key(d => d.status).entries(data);let categories = dataByCategories.map(d => d.key).sort();
let colorScale = d3.scaleLinear()             .domain([0, categories.length])             .range(["#00B9FA", "#F95002"])             .interpolate(d3.interpolateHcl);

And then we can fill the rectangles with colors from this scale. Putting together everything we've seen so far, here is the code:

然后我们可以用此比例尺的颜色填充矩形。 将到目前为止我们所看到的所有内容放在一起,下面是代码:

d3.json("projects.json", function(error, data) {            chart(data.projetos);        });
function chart(data) {    var dateFormat = d3.timeParse("%d/%m/%Y");    var timeScale = d3.scaleTime()                   .domain(d3.extent(data, d => dateFormat(d.date)))                   .range([0, 500]);      let dataByDates = d3.nest().key(d => d.date).entries(data);    let tickValues = dataByDates.map(d => dateFormat(d.key));      let dataByCategories = d3.nest().key(d => d.status).entries(data);    let categories = dataByCategories.map(d => d.key).sort();    let colorScale = d3.scaleLinear()                 .domain([0, categories.length])                 .range(["#00B9FA", "#F95002"])                 .interpolate(d3.interpolateHcl);      var xAxis = d3.axisBottom()                .scale(timeScale)                .tickValues(tickValues)                .tickSize(250, 0, 0)                .tickSizeOuter(0);    var grid = d3.select("svg").append('g').call(xAxis);      yScale = d3.scaleLinear().domain([0, data.length]).range([0, 250]);      var projects = d3.select("svg")                   .append('g')                   .selectAll("this_is_empty")                   .data(data)                   .enter();      var barWidth = 200;      var innerRects = projects.append("rect")                  .attr("rx", 3)                  .attr("ry", 3)                  .attr("x", (d,i) => timeScale(dateFormat(d.date)) - barWidth/2)                  .attr("y", (d,i) => yScale(i))                  .attr("width", barWidth)                  .attr("height", 30)                  .attr("stroke", "none")                  .attr("fill", d => d3.rgb(colorScale(categories.indexOf(d.status))));      var rectText = projects.append("text")                  .text(d => d.label)                  .attr("x", d => timeScale(dateFormat(d.date)))                  .attr("y", (d,i) => yScale(i) + 20)                  .attr("font-size", 11)                  .attr("text-anchor", "middle")                  .attr("text-height", 30)                  .attr("fill", "#fff"); }

And with that we have the raw structure of our visualization.

这样,我们便有了可视化的原始结构。

Well done.

做得好。

创建可重复使用的图表 (Creating a reusable chart)

The result shows that there are no margins. Also, if we want to display this graph on another page, we need to copy the entire code. To solve these issues, let’s build a reusable chart and just import it. To learn more about charts, click here. To see a previous tutorial I wrote about reusable charts, click here.

结果表明没有边距。 另外,如果我们想在另一个页面上显示此图,则需要复制整个代码。 为了解决这些问题,让我们构建一个可重用的图表并将其导入。 要了解有关图表的更多信息,请单击此处 。 要查看我之前写的有关可重用图表的教程,请单击此处

The structure to create a reusable chart is always the same. I created a tool to generate one. In this graph, I want to set:

创建可重用图表的结构始终相同。 我创建了一个生成工具。 在此图中,我要设置:

  • The data (of course)

    数据(当然)
  • The values for width, height, and margins

    宽度,高度和边距的值
  • A time scale for the x value of the rectangles

    x的时间标度 矩形的值

  • A scale for the y value for the rectangles

    矩形的y值的比例
  • A scale for the color

    颜色的比例
  • The values for xScale, yScale , and colorScale

    xScaleyScalecolorScale

  • The values for the start and end of each task and the height of each bar

    每个任务的开始和结束的值以及每个条的高度

I then pass this to the function I've created:

然后,将其传递给我创建的函数:

chart: ganttAlikeChartwidth: 800height: 600margin: {top: 20, right: 100, bottom: 20, left:100}xScale: d3.scaleTime()yScale: d3.scaleLinear()colorScale: d3.scaleLinear()xValue: d => d.datecolorValue: d => d.statusbarHeight: 30barWidth: 100dateFormat: d3.timeParse("%d/%m/%Y")

Which gives me this:

这给了我这个:

function  ganttAlikeChart(){width = 800;height = 600;margin = {top: 20, right: 100, bottom: 20, left:100};xScale = d3.scaleTime();yScale = d3.scaleLinear();colorScale = d3.scaleLinear();xValue = d => d.date;colorValue = d => d.status;barHeight = 30;barWidth = 100;dateFormat = d3.timeParse("%d/%m/%Y");function chart(selection) { selection.each(function(data) {   var svg = d3.select(this).selectAll("svg").data([data]).enter().append("svg");   svg.attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom);  var gEnter = svg.append("g");  var mainGroup = svg.select("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");})}
[...]
return chart;}

Now we just need to fill this template with the code we created before. I also made some changes to the CSS and added a tooltip.

现在,我们只需要使用我们之前创建的代码来填充此模板。 我还对CSS进行了一些更改并添加了工具提示。

And that's it.

就是这样。

You can check out the entire code here.

您可以在此处查看整个代码。

Thanks for reading! ?

谢谢阅读! ?

Did you found this article helpful? I try my best to write a deep dive article each month, you can receive an email when I publish a new one.

您觉得这篇文章对您有帮助吗? 我每个月都会尽力写一篇深入的文章, 当我发布新文章时,您会收到一封电子邮件

翻译自: https://www.freecodecamp.org/news/d3-visualizations-with-datasets-how-to-build-a-gantt-like-chart-9c9afa9b8d9d/

wps图表中如何插入甘特图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值