gpt4 book ai didi

javascript - 在 D3js 中的 x 轴上使用自定义刻度标签

转载 作者:行者123 更新时间:2023-11-30 00:30:18 25 4
gpt4 key购买 nike

我在 D3js 中制作了一个热图,x 轴是一年中的某天(1..365 之间的整数),y 轴是一天中的时间(1..24 之间的整数)。对于一年中的每个小时,一个点通过其颜色指示温度。

enter image description here

我试图找到一种方法,通过使用序数比例将月份的名称映射到一年中的正确日期,但没有成功。相反,我创建了一个带有月份名称的新 xScale 变量。问题是数据不再显示——现在我只看到 x 轴和 y 轴。

enter image description here

我想这是有道理的,因为 x 轴基于日期,并且每个点的 x 坐标基于整数 (1..365)。

所以我的问题是:

  1. 如何将年 (d.day) 转换为日期,是否有效?
  2. 如果我将 d.day 转换为日期,这将如何影响这样的计算:var days = d3.max(dataset, function(d) { return d.day ; }) - d3.min(数据集, function(d) { return d.day; });
  3. 这个问题有没有更好的解决方案?

下面是我的全部代码(抱歉我不知道在哪里设置限制):

d3.csv("data-gitignore/temperatures_nyc.csv", function(error, dataset) {
dataset.forEach(function(d) {
d.tOutC = +d.tOutC;
d.day = +d.day;
d.hour = +d.hour;
});

//----------------------------------
// VARIABLES
//----------------------------------

var days = d3.max(dataset, function(d) { return d.day; })
- d3.min(dataset, function(d) { return d.day; });
var hours = d3.max(dataset, function(d) { return d.hour; })
- d3.min(dataset, function(d) { return d.hour; });

var tMin = d3.min(dataset, function(d) { return d.tOutC; }),
tMax = d3.max(dataset, function(d) { return d.tOutC; });

var dotWidth = 1,
dotHeight = 3,
dotSpacing = 0.5;

var margin = {top: 0, right: 25, bottom: 40, left: 25},
width = (dotWidth * 2 + dotSpacing) * days,
height = (dotHeight * 2 + dotSpacing) * hours;//200 - margin.top - margin.bottom;

//----------------------------------
// FUNCTIONS
//----------------------------------

var xScale = d3.time.scale()
.domain([new Date(2015, 0, 1), new Date(2015, 11, 31)])
.range([0, width]);

var yScale = d3.scale.linear()
.domain([1, hours])
.range([(dotHeight * 2 + dotSpacing) * hours, dotHeight * 2 + dotSpacing]);

var colorScale = d3.scale.linear()
.domain([tMin-5, (tMax-tMin)/2, tMax-5])
.range(["#4575b4","#ffffdf", "#d73027"]);

var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(d3.time.months)
.tickFormat(d3.time.format("%b"));


// Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(2);

// Zoom behavior
var zoom = d3.behavior.zoom()
.scaleExtent([dotWidth, dotHeight])
.x(xScale)
.on("zoom", zoomHandler);

function zoomHandler() {
var t = zoom.translate(),
tx = t[0],
ty = t[1];

tx = Math.min(tx, 0);
tx = Math.max(tx, width - (dotWidth * 2 + dotSpacing) * days * d3.event.scale);
zoom.translate([tx, ty]);


svg.select(".x.axis").call(xAxis);
svg.selectAll("ellipse")
.attr("cx", function(d) { return xScale(d.day); })
.attr("cy", function(d) { return yScale(d.hour); })
.attr("rx", function(d) { return (dotWidth * d3.event.scale); });
}

// SVG canvas
var svg = d3.select("#chart")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.call(zoom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// Clip path
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);


//----------------------------------
// DRAW ELEMENTS ON SVG CANVAS
//----------------------------------


// Heatmap dots
svg.append("g")
.attr("clip-path", "url(#clip)")
.selectAll("ellipse")
.data(dataset)
.enter()
.append("ellipse")
.attr("cx", function(d) { return xScale(d.day); })
.attr("cy", function(d) { return yScale(d.hour); })
.attr("rx", dotWidth)
.attr("ry", dotHeight)
.attr("fill", function(d) { return colorScale(d.tOutC); });

//Create X axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + yScale(0) + ")")
.call(xAxis)

//Create Y axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);

});

最佳答案

首先,将一年的第一天作为引用日期,date0。如果年份是 2014 年,那么它看起来像这样:

var date0 = Date.UTC(2014, 0);// Midnight on January 1st, 2014

date0 是自 1970 年以来的毫秒数。要验证这一点,您可以说

console.log(new Date(date0).toUTCString);

//> "Wed, 01 Jan 2014 00:00:00 GMT"

(请注意此处使用的是 UTC。最好在任何地方都使用 UTC 日期,因为这样可以确保用户无论在哪个时区都能看到正确的日期)。

鉴于此,您可以像这样轻松地为一年中的任何小时+一天创建一个日期对象:

// constants
var msPerHour = 3600000,
msPerDay = 24 * 3600000;

var after3days8hours = new Date(date0 + 3 * msPerDay + 8 * msPerHour);
console.log(after3days8hours.toUTCString())

//> "Sat, 04 Jan 2014 08:00:00 GMT"

现在您可以计算数据集中每个 CSV 行的日期:

dataset.forEach(function(d) {
d.tOutC = +d.tOutC;
d.day = +d.day;
d.hour = +d.hour;
d.date = new Date(date0 + d.day * msPerDay + d.hour * msPerDay)
});

这回答了问题 #1。

关于问题 #2:完成所有这些将使您能够根据需要计算最小值/最大值:

d3.max(dataset, function(d) { return d.date; })

d3.min(dataset, function(d) { return d.date; });

即使 d.date 是一个 Date 对象,JavaScript 也应该为您将它转换回毫秒数。此外,即使您选择跳过实例化所有这些 Date 对象,以上所有内容都可以正常工作。如:

// without new Date
d.date = date0 + d.day * msPerDay + d.hour * msPerDay;

但是 d3.time.scale 需要传递日期而不是数字,所以例如 xScale(d.date) 需要是 xScale(new Date(d.date)) 如果 d.date 是一个数字。如果您曾经看到 d3 出现控制台错误,请怀疑您可能忘记了这一点并输入了数字而不是日期。

对于 cx 计算,对于任何给定的时间,您需要找到当天的午夜。您可以像这样使用您的 d.day:

.attr("cx", function(d) {
return xScale(new Date(date0 + d.day * msPerDay));
})

或者,您可以像这样从 d.date 算起:

.attr("cx", function(d) {
var msAtMidnight = Math.floor(d.date / msPerDay) * msPerDay
return xScale(new Date(msAtMidnight));
})

要将 d.date 用于 cy,您可以说:

var msSinceMidnight = d.date % msPerDay

最后,因为您将使用 UTC 日期,所以您需要 UTC 时间标度而不是现有的常规时间标度。 D3 有适合你的规模:

var xScale = d3.time.scale.utc()

我认为 yScale 域应该是 [0, 23]

关于问题 #3:这可能是最好的解决方案,特别是因为 x 轴的刻度为月份(一月、二月等)可能是最合适的。为了获得这些滴答声,您有点必须使用时间尺度,因为每个月的天数是可变的,并且在没有“时间感知”尺度的情况下进行计算需要大量工作。

关于javascript - 在 D3js 中的 x 轴上使用自定义刻度标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29835408/

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