Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
qq_38905368
tensorflow
提交
dfb37b9b
T
tensorflow
项目概览
qq_38905368
/
tensorflow
与 Fork 源项目一致
从无法访问的项目Fork
通知
5
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
tensorflow
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
dfb37b9b
编写于
4月 08, 2016
作者:
A
A. Unique TensorFlower
提交者:
TensorFlower Gardener
4月 08, 2016
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Adding histogram chart component
Change: 119381434
上级
ec1e6c94
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
662 addition
and
12 deletion
+662
-12
tensorflow/tensorboard/components/tf-backend/backend.ts
tensorflow/tensorboard/components/tf-backend/backend.ts
+61
-5
tensorflow/tensorboard/components/tf-backend/test/backendTests.ts
...ow/tensorboard/components/tf-backend/test/backendTests.ts
+68
-7
tensorflow/tensorboard/components/tf-histogram-dashboard/rebin.ts
...ow/tensorboard/components/tf-histogram-dashboard/rebin.ts
+40
-0
tensorflow/tensorboard/components/tf-histogram-dashboard/test/index.html
...orboard/components/tf-histogram-dashboard/test/index.html
+13
-0
tensorflow/tensorboard/components/tf-histogram-dashboard/test/rebinTests.ts
...oard/components/tf-histogram-dashboard/test/rebinTests.ts
+75
-0
tensorflow/tensorboard/components/tf-histogram-dashboard/tf-vz-histogram-series.html
...onents/tf-histogram-dashboard/tf-vz-histogram-series.html
+405
-0
未找到文件。
tensorflow/tensorboard/components/tf-backend/backend.ts
浏览文件 @
dfb37b9b
...
...
@@ -44,13 +44,23 @@ module TF.Backend {
export
interface
Histogram
{
min
:
number
;
max
:
number
;
nItems
:
number
;
sum
:
number
;
sumSquares
:
number
;
nItems
?
:
number
;
sum
?
:
number
;
sumSquares
?
:
number
;
bucketRightEdges
:
number
[];
bucketCounts
:
number
[];
}
export
interface
HistogramBin
{
x
:
number
,
dx
:
number
,
y
:
number
}
export
type
HistogramSeriesDatum
=
HistogramSeries
&
Datum
;
export
interface
HistogramSeries
{
bins
:
HistogramBin
[]
}
export
type
ImageDatum
=
Datum
&
Image
export
interface
Image
{
width
:
number
;
...
...
@@ -169,11 +179,20 @@ module TF.Backend {
/**
* Return a promise containing HistogramDatums for given run and tag.
*/
public
histogram
(
tag
:
string
,
run
:
string
):
Promise
<
Array
<
HistogramDatum
>>
{
public
histogram
(
tag
:
string
,
run
:
string
):
Promise
<
Array
<
Histogram
Series
Datum
>>
{
let
p
:
Promise
<
TupleData
<
HistogramTuple
>
[]
>
;
let
url
=
this
.
router
.
histograms
(
tag
,
run
);
p
=
this
.
requestManager
.
request
(
url
);
return
p
.
then
(
map
(
detupler
(
createHistogram
)));
return
p
.
then
(
map
(
detupler
(
createHistogram
)))
.
then
(
function
(
histos
)
{
return
histos
.
map
(
function
(
histo
,
i
)
{
return
{
wall_time
:
histo
.
wall_time
,
step
:
histo
.
step
,
bins
:
convertBins
(
histo
)
};
});
});
}
/**
...
...
@@ -277,6 +296,43 @@ module TF.Backend {
};
};
/**
* Takes histogram data as stored by tensorboard backend and converts it to
* the standard d3 histogram data format to make it more compatible and easier to
* visualize. When visualizing histograms, having the left edge and width makes
* things quite a bit easier.
*
* @param {histogram} Histogram - A histogram from tensorboard backend.
* @return {HistogramBin[]} - Each bin has an x (left edge), a dx (width), and a y (count).
*
* If given rightedges are inclusive, then these left edges (x) are exclusive.
*/
export
function
convertBins
(
histogram
:
Histogram
)
{
if
(
histogram
.
bucketRightEdges
.
length
!==
histogram
.
bucketCounts
.
length
)
{
throw
(
new
Error
(
"
Edges and counts are of different lengths.
"
))
}
var
previousRightEdge
=
histogram
.
min
;
return
histogram
.
bucketRightEdges
.
map
(
function
(
rightEdge
:
number
,
i
:
number
)
{
// Use the previous bin's rightEdge as the new leftEdge
var
left
=
previousRightEdge
;
// We need to clip the rightEdge because right-most edge can be
// infinite-sized
var
right
=
Math
.
min
(
histogram
.
max
,
rightEdge
);
// Store rightEdgeValue for next iteration
previousRightEdge
=
rightEdge
;
return
{
x
:
left
,
dx
:
right
-
left
,
y
:
histogram
.
bucketCounts
[
i
]
};
});
}
// The following interfaces (TupleData, HistogramTuple, CompressedHistogramTuple,
// and ImageMetadata) describe how the data is sent over from the backend, and thus
// wall_time, step, value
...
...
tensorflow/tensorboard/components/tf-backend/test/backendTests.ts
浏览文件 @
dfb37b9b
...
...
@@ -78,13 +78,7 @@ module TF.Backend {
backend
.
histogram
(
"
histo1
"
,
"
run1
"
).
then
((
histos
)
=>
{
var
histo
=
histos
[
0
];
assertIsDatum
(
histo
);
assert
.
isNumber
(
histo
.
min
);
assert
.
isNumber
(
histo
.
max
);
assert
.
isNumber
(
histo
.
sum
);
assert
.
isNumber
(
histo
.
sumSquares
);
assert
.
isNumber
(
histo
.
nItems
);
assert
.
instanceOf
(
histo
.
bucketRightEdges
,
Array
);
assert
.
instanceOf
(
histo
.
bucketRightEdges
,
Array
);
assert
.
instanceOf
(
histo
.
bins
,
Array
);
done
();
});
});
...
...
@@ -156,4 +150,71 @@ module TF.Backend {
assert
.
deepEqual
(
getTags
(
empty2
),
[]);
});
});
describe
(
"
Verify that the histogram format conversion works.
"
,
function
()
{
function
assertHistogramEquality
(
h1
,
h2
)
{
h1
.
forEach
(
function
(
b1
,
i
)
{
var
b2
=
h2
[
i
];
assert
.
closeTo
(
b1
.
x
,
b2
.
x
,
1
e
-
10
);
assert
.
closeTo
(
b1
.
dx
,
b2
.
dx
,
1
e
-
10
);
assert
.
closeTo
(
b1
.
y
,
b2
.
y
,
1
e
-
10
);
});
}
it
(
"
Throws and error if the inputs are of different lengths
"
,
function
()
{
assert
.
throws
(
function
()
{
convertBins
({
bucketRightEdges
:[
0
],
bucketCounts
:[
1
,
2
],
min
:
1
,
max
:
2
});
},
"
Edges and counts are of different lengths.
"
)
});
it
(
"
Handles data with no bins
"
,
function
()
{
assert
.
deepEqual
(
convertBins
({
bucketRightEdges
:
[],
bucketCounts
:
[],
min
:
0
,
max
:
0
}),
[]);
});
it
(
"
Handles data with one bin
"
,
function
()
{
var
counts
=
[
1
];
var
rightEdges
=
[
1.21
e
-
12
];
var
histogram
=
[
{
x
:
1.1
e
-
12
,
dx
:
1.21
e
-
12
-
1.1
e
-
12
,
y
:
1
}
];
var
newHistogram
=
convertBins
({
bucketRightEdges
:
rightEdges
,
bucketCounts
:
counts
,
min
:
1.1
e
-
12
,
max
:
1.21
e
-
12
});
assertHistogramEquality
(
newHistogram
,
histogram
);
});
it
(
"
Handles data with two bins.
"
,
function
()
{
var
counts
=
[
1
,
2
];
var
rightEdges
=
[
1.1
e
-
12
,
1.21
e
-
12
];
var
histogram
=
[
{
x
:
1.0
e
-
12
,
dx
:
1.1
e
-
12
-
1.0
e
-
12
,
y
:
1
},
{
x
:
1.1
e
-
12
,
dx
:
1.21
e
-
12
-
1.1
e
-
12
,
y
:
2
}
];
var
newHistogram
=
convertBins
({
bucketRightEdges
:
rightEdges
,
bucketCounts
:
counts
,
min
:
1.0
e
-
12
,
max
:
1.21
e
-
12
});
assertHistogramEquality
(
newHistogram
,
histogram
);
});
it
(
"
Handles a domain that crosses zero, but doesn't include zero as an edge.
"
,
function
()
{
var
counts
=
[
1
,
2
];
var
rightEdges
=
[
-
1.0
e
-
12
,
1.0
e
-
12
];
var
histogram
=
[
{
x
:
-
1.1
e
-
12
,
dx
:
1.1
e
-
12
-
1.0
e
-
12
,
y
:
1
},
{
x
:
-
1.0
e
-
12
,
dx
:
2.0
e
-
12
,
y
:
2
}
];
var
newHistogram
=
convertBins
({
bucketRightEdges
:
rightEdges
,
bucketCounts
:
counts
,
min
:
-
1.1
e
-
12
,
max
:
1.0
e
-
12
});
assertHistogramEquality
(
newHistogram
,
histogram
);
});
it
(
"
Handles a right-most right edge that extends to very large number.
"
,
function
()
{
var
counts
=
[
1
,
2
,
3
];
var
rightEdges
=
[
0
,
1.0
e
-
12
,
1.0e14
];
var
histogram
=
[
{
x
:
-
1.0
e
-
12
,
dx
:
1.0
e
-
12
,
y
:
1
},
{
x
:
0
,
dx
:
1.0
e
-
12
,
y
:
2
},
{
x
:
1.0
e
-
12
,
dx
:
1.1
e
-
12
-
1.0
e
-
12
,
y
:
3
}
];
var
newHistogram
=
convertBins
({
bucketRightEdges
:
rightEdges
,
bucketCounts
:
counts
,
min
:
-
1.0
e
-
12
,
max
:
1.1
e
-
12
});
assertHistogramEquality
(
newHistogram
,
histogram
);
});
});
}
tensorflow/tensorboard/components/tf-histogram-dashboard/rebin.ts
0 → 100644
浏览文件 @
dfb37b9b
module
TF
.
Histogram
{
/**
* Re-bins histogram data into uniform-width bins. Assumes a uniform distribution of values in given bins.
*
* @param {HistogramBin[]} bins - The original histogram data,
* @param {number} numberOfBins - The number of uniform-width bins to split the data into.
* @return {HistogramBin[]} - Re-binned histogram data. Does not modify original data, returns a new array.
*/
export
function
rebinHistogram
(
bins
:
TF
.
Backend
.
HistogramBin
[],
numberOfBins
:
number
)
{
if
(
bins
.
length
===
0
)
return
[];
var
oldBinsXExtent
=
[
d3
.
min
(
bins
,
function
(
old
:
any
)
{
return
old
.
x
;
}),
d3
.
max
(
bins
,
function
(
old
:
any
)
{
return
old
.
x
+
old
.
dx
;
})
];
var
newDx
:
number
=
(
oldBinsXExtent
[
1
]
-
oldBinsXExtent
[
0
])
/
numberOfBins
;
var
newBins
:
TF
.
Backend
.
HistogramBin
[]
=
d3
.
range
(
oldBinsXExtent
[
0
],
oldBinsXExtent
[
1
],
newDx
).
map
(
function
(
newX
)
{
// Take the count of each existing bin, multiply it by the proportion of
// overlap with the new bin, then sum and store as the count for new
// bin. If no overlap, will add zero, if 100% overlap, will include full
// count into new bin.
var
newY
=
d3
.
sum
(
bins
.
map
(
function
(
old
)
{
var
intersectDx
=
Math
.
min
(
old
.
x
+
old
.
dx
,
newX
+
newDx
)
-
Math
.
max
(
old
.
x
,
newX
);
return
(
intersectDx
>
0
)
?
(
intersectDx
/
old
.
dx
)
*
old
.
y
:
0
;
}));
return
{
x
:
newX
,
dx
:
newDx
,
y
:
newY
};
});
return
newBins
;
}
}
tensorflow/tensorboard/components/tf-histogram-dashboard/test/index.html
0 → 100644
浏览文件 @
dfb37b9b
<!doctype html>
<html>
<head>
<meta
charset=
"utf-8"
>
<script
src=
"../../web-component-tester/browser.js"
></script>
<script
src=
"../../webcomponentsjs/webcomponents-lite.min.js"
></script>
<link
rel=
"import"
href=
"../../tf-imports/d3.html"
>
</head>
<body>
<script
src=
"../rebin.js"
></script>
<script
src=
"rebinTests.js"
></script>
</body>
</html>
tensorflow/tensorboard/components/tf-histogram-dashboard/test/rebinTests.ts
0 → 100644
浏览文件 @
dfb37b9b
/* Copyright 2015 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
module
TF
.
Histogram
{
let
assert
=
chai
.
assert
;
describe
(
"
Rebin
"
,
function
()
{
var
assertHistogramEquality
=
function
(
h1
,
h2
)
{
h1
.
forEach
(
function
(
b1
,
i
)
{
var
b2
=
h2
[
i
];
assert
.
closeTo
(
b1
.
x
,
b2
.
x
,
1
e
-
10
);
assert
.
closeTo
(
b1
.
dx
,
b2
.
dx
,
1
e
-
10
);
assert
.
closeTo
(
b1
.
y
,
b2
.
y
,
1
e
-
10
);
});
}
//
// Rebinning
//
it
(
"
Returns an empty array if you don't have any bins
"
,
function
()
{
assert
.
deepEqual
(
rebinHistogram
([],
10
),
[]);
});
it
(
"
Collapses two bins into one.
"
,
function
()
{
var
histogram
=
[
{
x
:
0
,
dx
:
1
,
y
:
1
},
{
x
:
1
,
dx
:
1
,
y
:
2
}
];
var
oneBin
=
[
{
x
:
0
,
dx
:
2
,
y
:
3
}
];
assertHistogramEquality
(
rebinHistogram
(
histogram
,
1
),
oneBin
);
});
it
(
"
Splits one bin into two.
"
,
function
()
{
var
histogram
=
[
{
x
:
0
,
dx
:
1
,
y
:
3
}
];
var
twoBin
=
[
{
x
:
0
,
dx
:
0.5
,
y
:
1.5
},
{
x
:
0.5
,
dx
:
0.5
,
y
:
1.5
}
];
assertHistogramEquality
(
rebinHistogram
(
histogram
,
2
),
twoBin
);
});
it
(
"
Regularizes non-uniform bins.
"
,
function
()
{
var
histogram
=
[
{
x
:
0
,
dx
:
2
,
y
:
3
},
{
x
:
2
,
dx
:
3
,
y
:
3
},
{
x
:
5
,
dx
:
1
,
y
:
1
}
];
var
twoBin
=
[
{
x
:
0
,
dx
:
3
,
y
:
4
},
{
x
:
3
,
dx
:
3
,
y
:
3
}
];
assertHistogramEquality
(
rebinHistogram
(
histogram
,
2
),
twoBin
);
});
});
}
tensorflow/tensorboard/components/tf-histogram-dashboard/tf-vz-histogram-series.html
0 → 100644
浏览文件 @
dfb37b9b
<link
rel=
"import"
href=
"../polymer/polymer.html"
>
<dom-module
id=
"tf-vz-histogram-series"
>
<template>
<style>
:host
{
display
:
block
;
}
svg
{
font-family
:
roboto
,
sans-serif
;
}
.background
{
fill-opacity
:
0
;
fill
:
red
;
}
.histogram
{
pointer-events
:
none
;
}
.hover
{
font-size
:
9px
;
dominant-baseline
:
middle
;
opacity
:
0
;
}
.hover
circle
{
stroke
:
white
;
stroke-opacity
:
0.5
;
stroke-width
:
1px
;
}
.baseline
{
stroke
:
black
;
stroke-opacity
:
0.1
;
}
.outline
{
fill
:
none
;
stroke
:
white
;
stroke-opacity
:
0.5
;
}
.x-axis-hover
{
pointer-events
:
none
;
}
.x-axis-hover
.label
{
opacity
:
0
;
font-weight
:
bold
;
font-size
:
11px
;
text-anchor
:
end
;
}
.x-axis-hover
text
{
text-anchor
:
middle
;
}
.x-axis-hover
line
{
stroke
:
black
;
}
.x-axis-hover
rect
{
fill
:
white
;
}
.gradient
{
}
.axis
{
font-size
:
10px
;
fill
:
#aaa
;
}
.axis
path
.domain
{
fill
:
none
;
}
.axis
.tick
line
{
stroke
:
#ddd
;
}
.axis.slice
{
opacity
:
0
;
}
.axis.slice
.tick
line
{
stroke-dasharray
:
2
;
}
.small
.axis
text
{
display
:
none
;
}
.small
.axis
.tick
:first-of-type
text
{
display
:
block
;
}
.small
.axis
.tick
:last-of-type
text
{
display
:
block
;
}
.medium
.axis
text
{
display
:
none
;
}
.medium
.axis
.tick
:nth-child
(
2
n
+
1
)
text
{
display
:
block
;
}
.large
.axis
text
{
display
:
none
;
}
.large
.axis
.tick
:nth-child
(
2
n
+
1
)
text
{
display
:
block
;
}
</style>
<svg
id=
"svg"
>
<g>
<g
class=
"axis x"
></g>
<g
class=
"axis y"
></g>
<g
class=
"axis y slice"
></g>
<g
class=
"stage"
>
<rect
class=
"background"
></rect>
</g>
<g
class=
"x-axis-hover"
></g>
</g>
</svg>
</template>
<script>
"
use strict
"
;
Polymer
({
is
:
"
tf-vz-histogram-series
"
,
properties
:
{
mode
:
{
type
:
String
,
value
:
"
offset
"
},
//offset | overlay
width
:
{
type
:
Number
,
value
:
500
},
height
:
{
type
:
Number
,
value
:
500
},
timeProperty
:
{
type
:
String
,
value
:
"
step
"
},
bins
:
{
type
:
String
,
value
:
"
bins
"
},
x
:
{
type
:
String
,
value
:
"
x
"
},
dx
:
{
type
:
String
,
value
:
"
dx
"
},
y
:
{
type
:
String
,
value
:
"
y
"
},
data
:
{
type
:
Array
,
value
:
function
(){
return
[{
step
:
0
,
bins
:
[{
x
:
0
,
dx
:
1
,
y
:
0
}]
},
{
step
:
1
,
bins
:
[{
x
:
0
,
dx
:
1
,
y
:
0
}]
}];}}
// type: HistogramSeriesDatum[] as described in tf-vz-histogram-series.d.ts
},
ready
:
function
()
{
// Polymer's way of scoping styles on nodes that d3 created
this
.
scopeSubtree
(
this
.
$
[
"
svg
"
],
true
);
},
draw
:
function
(
duration
)
{
//
// Data verification
//
if
(
!
(
this
.
data
.
length
>
0
))
throw
(
new
Error
(
"
Not enough steps in the data
"
));
if
(
!
this
.
data
[
0
].
hasOwnProperty
(
this
.
timeProperty
))
throw
(
new
Error
(
"
No time property of '
"
+
this
.
timeProperty
+
"
' in data
"
));
if
(
!
this
.
data
[
0
].
hasOwnProperty
(
this
.
bins
))
throw
(
new
Error
(
"
No bins property of '
"
+
this
.
bins
+
"
' in data
"
));
if
(
!
(
this
.
data
[
0
][
this
.
bins
].
length
>
0
))
throw
(
new
Error
(
"
Must have at least one bin in bins in data
"
));
if
(
!
this
.
data
[
0
][
this
.
bins
][
0
].
hasOwnProperty
(
this
.
x
))
throw
(
new
Error
(
"
No x property '
"
+
this
.
x
+
"
' on bins data
"
));
if
(
!
this
.
data
[
0
][
this
.
bins
][
0
].
hasOwnProperty
(
this
.
dx
))
throw
(
new
Error
(
"
No dx property '
"
+
this
.
dx
+
"
' on bins data
"
));
if
(
!
this
.
data
[
0
][
this
.
bins
][
0
].
hasOwnProperty
(
this
.
y
))
throw
(
new
Error
(
"
No y property '
"
+
this
.
y
+
"
' on bins data
"
));
//
// Initialization
//
var
timeProp
=
this
.
timeProperty
;
var
xProp
=
this
.
x
;
var
binsProp
=
this
.
bins
;
var
dxProp
=
this
.
dx
;
var
yProp
=
this
.
y
;
var
xAccessor
=
(
d
)
=>
d
[
xProp
];
var
yAccessor
=
(
d
)
=>
d
[
yProp
];
var
dxAccessor
=
(
d
)
=>
d
[
dxProp
];
var
xRightAccessor
=
(
d
)
=>
d
[
xProp
]
+
d
[
dxProp
];
var
timeAccessor
=
(
d
)
=>
d
[
timeProp
];
var
duration
=
duration
|
0
;
var
data
=
this
.
data
;
var
mode
=
this
.
mode
;
var
outerWidth
=
this
.
width
,
outerHeight
=
this
.
height
;
var
sliceHeight
,
margin
=
{
top
:
5
,
right
:
60
,
bottom
:
20
,
left
:
24
};
if
(
mode
===
"
offset
"
)
{
sliceHeight
=
outerHeight
/
2.5
;
margin
.
top
=
sliceHeight
+
5
;
}
else
{
sliceHeight
=
outerHeight
-
margin
.
top
-
margin
.
bottom
;
}
var
width
=
outerWidth
-
margin
.
left
-
margin
.
right
,
height
=
outerHeight
-
margin
.
top
-
margin
.
bottom
;
var
leftMin
=
d3
.
min
(
data
,
xAccessor
),
rightMax
=
d3
.
max
(
data
,
xRightAccessor
);
//
// Text formatters
//
var
formatTime
=
d3
.
time
.
format
(
"
%x
"
),
format
=
d3
.
format
(
"
.3n
"
);
//
// Calculate the extents
//
var
xExtents
=
data
.
map
(
function
(
d
,
i
)
{
return
[
d3
.
min
(
d
[
binsProp
],
xAccessor
),
d3
.
max
(
d
[
binsProp
],
xRightAccessor
)
];
});
var
yExtents
=
data
.
map
(
function
(
d
)
{
return
d3
.
extent
(
d
[
binsProp
],
yAccessor
);
});
//
// Scales and axis
//
var
outlineCanvasSize
=
500
;
var
yScale
=
(
timeProp
===
"
step
"
?
d3
.
scale
.
linear
()
:
d3
.
time
.
scale
())
.
domain
(
d3
.
extent
(
data
,
timeAccessor
))
.
range
([
0
,
(
mode
===
"
offset
"
?
height
:
0
)]);
var
ySliceScale
=
d3
.
scale
.
linear
()
.
domain
([
0
,
d3
.
max
(
data
,
function
(
d
,
i
)
{
return
yExtents
[
i
][
1
];
})])
.
range
([
sliceHeight
,
0
]);
var
yLineScale
=
d3
.
scale
.
linear
()
.
domain
(
ySliceScale
.
domain
())
.
range
([
outlineCanvasSize
,
0
]);
var
xScale
=
d3
.
scale
.
linear
()
.
domain
([
d3
.
min
(
data
,
function
(
d
,
i
)
{
return
xExtents
[
i
][
0
];
}),
d3
.
max
(
data
,
function
(
d
,
i
)
{
return
xExtents
[
i
][
1
];
})
])
.
nice
()
.
range
([
0
,
width
]);
var
xLineScale
=
d3
.
scale
.
linear
()
.
domain
(
xScale
.
domain
())
.
range
([
0
,
outlineCanvasSize
]);
var
outlineColor
=
d3
.
scale
.
linear
()
.
domain
(
d3
.
extent
(
data
,
timeAccessor
))
.
range
([
"
#FFA726
"
,
"
#BF360C
"
])
.
interpolate
(
d3
.
interpolateHcl
);
var
xAxis
=
d3
.
svg
.
axis
()
.
scale
(
xScale
)
.
ticks
(
Math
.
max
(
2
,
width
/
20
))
.
orient
(
"
bottom
"
);
var
yAxis
=
d3
.
svg
.
axis
()
.
scale
(
yScale
)
.
ticks
(
Math
.
max
(
2
,
width
/
20
))
.
orient
(
"
right
"
);
var
ySliceAxis
=
d3
.
svg
.
axis
()
.
scale
(
ySliceScale
)
.
ticks
(
Math
.
max
(
2
,
width
/
20
))
.
tickSize
(
width
+
5
)
.
orient
(
"
right
"
);
var
path
=
d3
.
svg
.
area
()
.
interpolate
(
"
linear
"
)
.
x
(
function
(
d
)
{
return
xLineScale
(
d
[
xProp
]
+
d
[
dxProp
]
/
2
);
})
.
y0
(
function
(
d
)
{
return
yLineScale
(
0
);
})
.
y1
(
function
(
d
)
{
return
yLineScale
(
d
[
yProp
]);
});
//
// Render
//
var
svgNode
=
this
.
$
.
svg
;
var
svg
=
d3
.
select
(
svgNode
)
var
svgTransition
=
svg
.
transition
().
duration
(
duration
)
.
attr
(
"
width
"
,
outerWidth
)
.
attr
(
"
height
"
,
outerHeight
);
var
g
=
svg
.
select
(
"
g
"
)
.
classed
(
"
small
"
,
function
()
{
return
(
width
>
0
&&
width
<=
150
);
})
.
classed
(
"
medium
"
,
function
()
{
return
(
width
>
150
&&
width
<=
300
);
})
.
classed
(
"
large
"
,
function
()
{
return
(
width
>
300
);
})
var
gTransition
=
svgTransition
.
select
(
"
g
"
)
.
attr
(
"
transform
"
,
"
translate(
"
+
margin
.
left
+
"
,
"
+
margin
.
top
+
"
)
"
);
var
bisect
=
d3
.
bisector
(
xRightAccessor
).
left
;
var
stage
=
g
.
select
(
"
.stage
"
)
.
on
(
"
mouseover
"
,
function
()
{
hoverUpdate
.
transition
().
style
(
"
opacity
"
,
1
);
edgeLabelUpdate
.
transition
().
style
(
"
opacity
"
,
1
)
})
.
on
(
"
mouseout
"
,
function
()
{
hoverUpdate
.
transition
().
style
(
"
opacity
"
,
0
);
edgeLabelUpdate
.
transition
().
style
(
"
opacity
"
,
0
)
})
.
on
(
"
mousemove
"
,
function
()
{
var
m
=
d3
.
mouse
(
this
),
v
=
xScale
.
invert
(
m
[
0
]);
function
hoverXIndex
(
d
)
{
return
Math
.
min
(
d
[
binsProp
].
length
-
1
,
bisect
(
d
[
binsProp
],
v
));
}
var
lastSliceData
;
hoverUpdate
.
attr
(
"
transform
"
,
function
(
d
)
{
var
index
=
hoverXIndex
(
d
);
lastSliceData
=
d
;
return
"
translate(
"
+
xScale
(
d
[
binsProp
][
index
][
xProp
]
+
d
[
binsProp
][
index
][
dxProp
]
/
2
)
+
"
,
"
+
ySliceScale
(
d
[
binsProp
][
index
][
yProp
])
+
"
)
"
;
});
var
index
=
hoverXIndex
(
lastSliceData
);
edgeLabelUpdate
.
attr
(
"
transform
"
,
function
(
d
)
{
return
"
translate(
"
+
xScale
(
lastSliceData
[
binsProp
][
index
][
xProp
]
+
lastSliceData
[
binsProp
][
index
][
dxProp
]
/
2
)
+
"
,
"
+
height
+
"
)
"
;
})
.
select
(
"
text
"
)
.
text
(
function
(
d
)
{
return
format
(
lastSliceData
[
binsProp
][
index
][
xProp
]
+
lastSliceData
[
binsProp
][
index
][
dxProp
]
/
2
);
});
});
var
background
=
stage
.
select
(
"
.background
"
)
.
attr
(
"
transform
"
,
"
translate(
"
+
-
margin
.
left
+
"
,
"
+
-
margin
.
top
+
"
)
"
)
.
attr
(
"
width
"
,
outerWidth
)
.
attr
(
"
height
"
,
outerHeight
);
var
histogram
=
stage
.
selectAll
(
"
.histogram
"
).
data
(
data
,
function
(
d
)
{
return
d
[
timeProp
];
}),
histogramExit
=
histogram
.
exit
().
remove
(),
histogramEnter
=
histogram
.
enter
().
append
(
"
g
"
).
attr
(
"
class
"
,
"
histogram
"
),
histogramUpdate
=
histogram
.
sort
(
function
(
a
,
b
)
{
return
a
[
timeProp
]
-
b
[
timeProp
];
}),
histogramTransition
=
gTransition
.
selectAll
(
"
.histogram
"
)
.
attr
(
"
transform
"
,
function
(
d
)
{
return
"
translate(0,
"
+
(
mode
===
"
offset
"
?
(
yScale
(
d
[
timeProp
])
-
sliceHeight
)
:
0
)
+
"
)
"
;
});
var
baselineEnter
=
histogramEnter
.
append
(
"
line
"
).
attr
(
"
class
"
,
"
baseline
"
),
baselineUpdate
=
histogramTransition
.
select
(
"
.baseline
"
)
.
style
(
"
stroke-opacity
"
,
function
(
d
)
{
return
(
mode
===
"
offset
"
?
0.1
:
0
);
})
.
attr
(
"
y1
"
,
sliceHeight
)
.
attr
(
"
y2
"
,
sliceHeight
)
.
attr
(
"
x2
"
,
width
);
var
outlineEnter
=
histogramEnter
.
append
(
"
path
"
).
attr
(
"
class
"
,
"
outline
"
),
outlineUpdate
=
histogramUpdate
.
select
(
"
.outline
"
)
.
attr
(
"
vector-effect
"
,
"
non-scaling-stroke
"
)
.
attr
(
"
d
"
,
function
(
d
)
{
return
path
(
d
[
binsProp
]);
})
.
style
(
"
stroke-width
"
,
1
),
outlineTransition
=
histogramTransition
.
select
(
"
.outline
"
)
.
attr
(
"
transform
"
,
"
scale(
"
+
width
/
outlineCanvasSize
+
"
,
"
+
sliceHeight
/
outlineCanvasSize
+
"
)
"
)
.
style
(
"
stroke
"
,
function
(
d
)
{
return
(
mode
===
"
offset
"
?
"
white
"
:
outlineColor
(
d
[
timeProp
]));
})
.
style
(
"
fill-opacity
"
,
function
(
d
)
{
return
(
mode
===
"
offset
"
?
1
:
0
);
})
.
style
(
"
fill
"
,
function
(
d
)
{
return
outlineColor
(
d
[
timeProp
]);
});
var
hoverEnter
=
histogramEnter
.
append
(
"
g
"
)
.
attr
(
"
class
"
,
"
hover
"
)
.
style
(
"
fill
"
,
function
(
d
)
{
return
outlineColor
(
d
[
timeProp
]);
}),
hoverUpdate
=
histogramUpdate
.
select
(
"
.hover
"
);
hoverEnter
.
append
(
"
circle
"
)
.
attr
(
"
r
"
,
2
);
hoverEnter
.
append
(
"
text
"
)
.
style
(
"
display
"
,
"
none
"
)
.
style
(
"
stroke
"
,
"
white
"
)
.
style
(
"
stroke-width
"
,
2
)
.
attr
(
"
dx
"
,
4
);
hoverEnter
.
append
(
"
text
"
)
.
style
(
"
display
"
,
"
none
"
)
.
attr
(
"
dx
"
,
4
);
var
edgeLabel
=
g
.
select
(
"
.x-axis-hover
"
).
selectAll
(
"
.label
"
).
data
([
"
x
"
]),
edgeLabelEnter
=
edgeLabel
.
enter
().
append
(
"
g
"
).
attr
(
"
class
"
,
"
label
"
),
edgeLabelUpdate
=
edgeLabel
;
edgeLabelEnter
.
append
(
"
rect
"
)
.
attr
(
"
x
"
,
-
20
)
.
attr
(
"
y
"
,
6
)
.
attr
(
"
width
"
,
40
)
.
attr
(
"
height
"
,
14
)
edgeLabelEnter
.
append
(
"
line
"
)
.
attr
(
"
x1
"
,
0
)
.
attr
(
"
x2
"
,
0
)
.
attr
(
"
y1
"
,
0
)
.
attr
(
"
y2
"
,
6
);
edgeLabelEnter
.
append
(
"
text
"
)
.
attr
(
"
dy
"
,
18
);
gTransition
.
select
(
"
.y.axis.slice
"
)
.
style
(
"
opacity
"
,
mode
===
"
offset
"
?
0
:
1
)
.
attr
(
"
transform
"
,
"
translate(0,
"
+
(
mode
===
"
offset
"
?
-
sliceHeight
:
0
)
+
"
)
"
)
.
call
(
ySliceAxis
);
gTransition
.
select
(
"
.x.axis
"
)
.
attr
(
"
transform
"
,
"
translate(0,
"
+
height
+
"
)
"
)
.
call
(
xAxis
);
gTransition
.
select
(
"
.y.axis
"
)
.
style
(
"
opacity
"
,
mode
===
"
offset
"
?
1
:
0
)
.
attr
(
"
transform
"
,
"
translate(
"
+
width
+
"
,
"
+
(
mode
===
"
offset
"
?
0
:
height
)
+
"
)
"
)
.
call
(
yAxis
);
}
});
</script>
</dom-module>
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录