我有一个基于 D3.js 的组合/条形图。 x轴域包含最小和最大日期,条形图基于值。但是最后一个柱(矩形)在图表之外。我可以通过强制将其引入(手动),但它不会反映数据。
var data = [
{
fcst_valid_local: "2018-11-13T14:00:00-0600",
pop: 20,
rh: 67,
temp: 38,
wspd: 7
},
{
fcst_valid_local: "2018-11-14T15:00:00-0600",
pop: 15,
rh: 50,
temp: 39,
wspd: 8
},
{
fcst_valid_local: "2018-11-15T16:00:00-0600",
pop: 10,
rh: 90,
temp: 40,
wspd: 9
}
];
// Margins, width and height.
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 500 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
// Date parsing.
const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
data.forEach(function (d) {
d.date = parseDate(d.fcst_valid_local);
});
// Set scale domains.
var x = d3.scaleTime().range([0, width])
.domain(d3.extent(data, function (d) {
return d.date;
}));
var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
const y1 = d3.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, (d) => d.pop)]);
// Construct our SVG object.
const svg = d3.select('svg')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append('g').attr('class', 'container')
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Set x, y-left and y-right axis.
var xAxis = d3.axisBottom(x)
.ticks(d3.timeDay.every(1))
// .tickFormat(d3.timeFormat('%b %d, %H:%M'))
.tickSize(0).tickPadding(10);
var y0Axis = d3.axisLeft(y0)
.ticks(5).tickSize(0);
var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);
svg.append("g")
.attr("class", "x-axis axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y-axis axis")
.attr("transform", "translate(" + 0 + ", 0)")
.call(y0Axis);
svg.append("g")
.attr("class", "y-axis axis")
.attr("transform", "translate(" + width + ", 0)")
.call(y1Axis);
// Draw bars.
var bars = svg.selectAll(".precips")
.data(data);
bars.exit().remove();
bars.enter().append("rect")
.attr("class", "precip")
.attr("width", width / data.length - 50)
.attr("x", function (d) {
return x(d.date);
})
.attr("y", height)
.transition().duration(1000)
.attr("y", function (d) {
return y0(d.pop);
})
.attr("height", function (d) {
return height - y0(d.pop);
});
const lineRH = d3.line()
.x((d) => x(d['date']))
.y(d => y0(d['rh']));
svg.append('path')
.datum(data)
.attr('class', 'line')
.attr('fill', 'none')
.attr('stroke', 'red')
.attr('stroke-linejoin', 'round')
.attr('stroke-linecap', 'round')
.attr('stroke-width', 1.5)
.attr('d', lineRH);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
答案 0 :(得分:1)
添加一个比最后一个项目晚一点的虚拟数据项目
这里完成了硬编码,但是您可以根据最后一项的日期动态添加它
var data = [
{
fcst_valid_local: "2018-11-13T14:00:00-0600",
pop: 20,
rh: 67,
temp: 38,
wspd: 7
},
{
fcst_valid_local: "2018-11-14T15:00:00-0600",
pop: 15,
rh: 50,
temp: 39,
wspd: 8
},
{
fcst_valid_local: "2018-11-15T16:00:00-0600",
pop: 10,
rh: 90,
temp: 40,
wspd: 9
},
{
fcst_valid_local: "2018-11-16T01:00:00-0600"
}
];
// Margins, width and height.
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 500 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
// Date parsing.
const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
data.forEach(function (d) {
d.date = parseDate(d.fcst_valid_local);
});
// Set scale domains.
var x = d3.scaleTime().range([0, width])
.domain(d3.extent(data, function (d) {
return d.date;
}));
var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
const y1 = d3.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, (d) => d.pop)]);
// Construct our SVG object.
const svg = d3.select('svg')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append('g').attr('class', 'container')
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Set x, y-left and y-right axis.
var xAxis = d3.axisBottom(x)
.ticks(d3.timeDay.every(1))
// .tickFormat(d3.timeFormat('%b %d, %H:%M'))
.tickSize(0).tickPadding(10);
var y0Axis = d3.axisLeft(y0)
.ticks(5).tickSize(0);
var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);
svg.append("g")
.attr("class", "x-axis axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y-axis axis")
.attr("transform", "translate(" + 0 + ", 0)")
.call(y0Axis);
svg.append("g")
.attr("class", "y-axis axis")
.attr("transform", "translate(" + width + ", 0)")
.call(y1Axis);
// Draw bars.
var bars = svg.selectAll(".precips")
.data(data);
bars.exit().remove();
bars.enter().append("rect")
.attr("class", "precip")
.attr("width", width / data.length - 50)
.attr("x", function (d) {
return x(d.date);
})
.attr("y", height)
.transition().duration(1000)
.attr("y", function (d) {
return y0(d.pop);
})
.attr("height", function (d) {
return height - y0(d.pop);
});
const lineRH = d3.line()
.x((d) => x(d['date']))
.y(d => y0(d['rh']));
svg.append('path')
.datum(data)
.attr('class', 'line')
.attr('fill', 'none')
.attr('stroke', 'red')
.attr('stroke-linejoin', 'round')
.attr('stroke-linecap', 'round')
.attr('stroke-width', 1.5)
.attr('d', lineRH);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
答案 1 :(得分:1)
尽管答案已经被接受,但我想告诉您,您不必操纵<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
<uses-permission android:name="android.permission.INTERNET" />
<application
...
android:usesCleartextTraffic="true"
...>
...
</application>
</manifest>
(因为它也可以从API中获取),但是您可以在<UserControl.Resources>
<Style BasedOn="{StaticResource {x:Type Controls:Tile}}" TargetType="Controls:Tile" x:Key="ClosableTabButton">
<Setter Property="Width"
Value="17"/>
<Setter Property="Height"
Value="17"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<iconPacks:PackIconFontAwesome Margin="0,0,0,0"
Width="15"
Height="15"
Kind="PlusCircleSolid"
Rotation="45"
RenderTransformOrigin="0.5,0.5"
Foreground="#FFFFFF">
</iconPacks:PackIconFontAwesome>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<iconPacks:PackIconFontAwesome Margin="0,0,0,0"
Width="15"
Height="15"
Kind="PlusCircleSolid"
Rotation="45"
RenderTransformOrigin="0.5,0.5"
Foreground="#ff0000">
</iconPacks:PackIconFontAwesome>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
,因为这就是在此处设置正确的域的原因。
这是一个使用上面第二种方法并设置 x域的示例:
data
说明:这会将数据中的最大日期偏移1天,因此新的x.domain()
将会显示为:
var x = d3.scaleTime().range([0, width])
.domain([d3.min(data, function (d) {
return d.date;
}), d3.timeDay.offset(d3.max(data, function (d) { return d.date; }), 1)]);
其结果如下图所示:
x.domain()
(2) [Tue Nov 13 2018 15:00:00 GMT-0500 (Eastern Standard Time), Fri Nov 16 2018 17:00:00 GMT-0500 (Eastern Standard Time)]
我还尝试了var data = [
{
fcst_valid_local: "2018-11-13T14:00:00-0600",
pop: 20,
rh: 67,
temp: 38,
wspd: 7
},
{
fcst_valid_local: "2018-11-14T15:00:00-0600",
pop: 15,
rh: 50,
temp: 39,
wspd: 8
},
{
fcst_valid_local: "2018-11-15T16:00:00-0600",
pop: 10,
rh: 90,
temp: 40,
wspd: 9
}
];
// Margins, width and height.
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 500 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
// Date parsing.
const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");
data.forEach(function (d) {
d.date = parseDate(d.fcst_valid_local);
});
// Set scale domains.
var x = d3.scaleTime().range([0, width])
.domain([d3.min(data, function (d) {
return d.date;
}), d3.timeDay.offset(d3.max(data, function (d) { return d.date; }), 1)]);
var y0 = d3.scaleLinear().range([height, 0]).domain([0, 100]);
const y1 = d3.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, (d) => d.pop)]);
//console.log(x.domain());
// Construct our SVG object.
const svg = d3.select('svg')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append('g').attr('class', 'container')
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Set x, y-left and y-right axis.
var xAxis = d3.axisBottom(x)
.ticks(d3.timeDay.every(1))
// .tickFormat(d3.timeFormat('%b %d, %H:%M'))
.tickSize(0).tickPadding(10);
var y0Axis = d3.axisLeft(y0)
.ticks(5).tickSize(0);
var y1Axis = d3.axisRight(y1).ticks(5).tickSize(0);
svg.append("g")
.attr("class", "x-axis axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y-axis axis")
.attr("transform", "translate(" + 0 + ", 0)")
.call(y0Axis);
svg.append("g")
.attr("class", "y-axis axis")
.attr("transform", "translate(" + width + ", 0)")
.call(y1Axis);
// Draw bars.
var bars = svg.selectAll(".precips")
.data(data);
bars.exit().remove();
bars.enter().append("rect")
.attr("class", "precip")
.attr("width", width / data.length - 50)
.attr("x", function (d) {
return x(d.date);
})
.attr("y", height)
.transition().duration(1000)
.attr("y", function (d) {
return y0(d.pop);
})
.attr("height", function (d) {
return height - y0(d.pop);
});
const lineRH = d3.line()
.x((d) => x(d['date']) + (width / data.length - 50)/2)
.y(d => y0(d['rh']));
svg.append('path')
.datum(data)
.attr('class', 'line')
.attr('fill', 'none')
.attr('stroke', 'red')
.attr('stroke-linejoin', 'round')
.attr('stroke-linecap', 'round')
.attr('stroke-width', 1.5)
.attr('d', lineRH);
,有趣的部分是使用<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
内的d3时间间隔。随时与他们一起玩,如果您有任何疑问,请告诉我。
此外,我在行生成器fn中将.nice()
(路径)偏移了 barwidth / 2 。
.nice()
希望这也有帮助。