Adding nvd3 support
This commit is contained in:
parent
f1a64c0988
commit
89e92904e1
|
|
@ -1,5 +1,6 @@
|
|||
from wtforms import (
|
||||
Field, Form, SelectMultipleField, SelectField, TextField, TextAreaField)
|
||||
Field, Form, SelectMultipleField, SelectField, TextField, TextAreaField,
|
||||
BooleanField)
|
||||
from copy import copy
|
||||
|
||||
|
||||
|
|
@ -104,6 +105,21 @@ def form_factory(viz):
|
|||
"Font Size To",
|
||||
default="150",
|
||||
description="Font size for the biggest value in the list"),
|
||||
'show_brush': BooleanField(
|
||||
"Range Selector", default=True,
|
||||
description="Whether to display the time range interactive selector"),
|
||||
'show_legend': BooleanField(
|
||||
"Legend", default=True,
|
||||
description="Whether to display the legend (toggles)"),
|
||||
'rich_tooltip': BooleanField(
|
||||
"Rich Tooltip", default=True,
|
||||
description="The rich tooltip shows a list of all series for that point in time"),
|
||||
'y_axis_zero': BooleanField(
|
||||
"Y Axis Zero", default=False,
|
||||
description="Force the Y axis to start at 0 instead of the minimum value"),
|
||||
'y_log_scale': BooleanField(
|
||||
"Y Log", default=False,
|
||||
description="Use a log scale for the Y axis"),
|
||||
}
|
||||
field_css_classes = {k: ['form-control'] for k in px_form_fields.keys()}
|
||||
select2 = [
|
||||
|
|
@ -114,6 +130,8 @@ def form_factory(viz):
|
|||
field_css_classes['since'] += ['select2_free_since']
|
||||
field_css_classes['until'] += ['select2_free_until']
|
||||
field_css_classes['granularity'] += ['select2_free_granularity']
|
||||
for field in ('show_brush', 'show_legend', 'rich_tooltip'):
|
||||
field_css_classes[field] += ['input-sm']
|
||||
for field in select2:
|
||||
field_css_classes[field] += ['select2']
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,643 @@
|
|||
/* nvd3 version 1.8.1 (https://github.com/novus/nvd3) 2015-06-15 */
|
||||
.nvd3 .nv-axis {
|
||||
pointer-events:none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.nvd3 .nv-axis path {
|
||||
fill: none;
|
||||
stroke: #000;
|
||||
stroke-opacity: .75;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
.nvd3 .nv-axis path.domain {
|
||||
stroke-opacity: .75;
|
||||
}
|
||||
|
||||
.nvd3 .nv-axis.nv-x path.domain {
|
||||
stroke-opacity: 0;
|
||||
}
|
||||
|
||||
.nvd3 .nv-axis line {
|
||||
fill: none;
|
||||
stroke: #e5e5e5;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
.nvd3 .nv-axis .zero line,
|
||||
/*this selector may not be necessary*/ .nvd3 .nv-axis line.zero {
|
||||
stroke-opacity: .75;
|
||||
}
|
||||
|
||||
.nvd3 .nv-axis .nv-axisMaxMin text {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nvd3 .x .nv-axis .nv-axisMaxMin text,
|
||||
.nvd3 .x2 .nv-axis .nv-axisMaxMin text,
|
||||
.nvd3 .x3 .nv-axis .nv-axisMaxMin text {
|
||||
text-anchor: middle
|
||||
}
|
||||
|
||||
.nvd3 .nv-axis.nv-disabled {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.nvd3 .nv-bars rect {
|
||||
fill-opacity: .75;
|
||||
|
||||
transition: fill-opacity 250ms linear;
|
||||
-moz-transition: fill-opacity 250ms linear;
|
||||
-webkit-transition: fill-opacity 250ms linear;
|
||||
}
|
||||
|
||||
.nvd3 .nv-bars rect.hover {
|
||||
fill-opacity: 1;
|
||||
}
|
||||
|
||||
.nvd3 .nv-bars .hover rect {
|
||||
fill: lightblue;
|
||||
}
|
||||
|
||||
.nvd3 .nv-bars text {
|
||||
fill: rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
.nvd3 .nv-bars .hover text {
|
||||
fill: rgba(0,0,0,1);
|
||||
}
|
||||
|
||||
.nvd3 .nv-multibar .nv-groups rect,
|
||||
.nvd3 .nv-multibarHorizontal .nv-groups rect,
|
||||
.nvd3 .nv-discretebar .nv-groups rect {
|
||||
stroke-opacity: 0;
|
||||
|
||||
transition: fill-opacity 250ms linear;
|
||||
-moz-transition: fill-opacity 250ms linear;
|
||||
-webkit-transition: fill-opacity 250ms linear;
|
||||
}
|
||||
|
||||
.nvd3 .nv-multibar .nv-groups rect:hover,
|
||||
.nvd3 .nv-multibarHorizontal .nv-groups rect:hover,
|
||||
.nvd3 .nv-candlestickBar .nv-ticks rect:hover,
|
||||
.nvd3 .nv-discretebar .nv-groups rect:hover {
|
||||
fill-opacity: 1;
|
||||
}
|
||||
|
||||
.nvd3 .nv-discretebar .nv-groups text,
|
||||
.nvd3 .nv-multibarHorizontal .nv-groups text {
|
||||
font-weight: bold;
|
||||
fill: rgba(0,0,0,1);
|
||||
stroke: rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
/* boxplot CSS */
|
||||
.nvd3 .nv-boxplot circle {
|
||||
fill-opacity: 0.5;
|
||||
}
|
||||
|
||||
.nvd3 .nv-boxplot circle:hover {
|
||||
stroke: #AAA;
|
||||
}
|
||||
|
||||
.nvd3 .nv-boxplot rect:hover {
|
||||
fill-opacity: 1;
|
||||
}
|
||||
|
||||
.nvd3 line.nv-boxplot-median {
|
||||
stroke: black;
|
||||
}
|
||||
|
||||
.nv-boxplot-tick:hover {
|
||||
stroke-width: 2.5px;
|
||||
}
|
||||
/* bullet */
|
||||
.nvd3.nv-bullet { font: 10px sans-serif; }
|
||||
.nvd3.nv-bullet .nv-measure { fill-opacity: .8; }
|
||||
.nvd3.nv-bullet .nv-measure:hover { fill-opacity: 1; }
|
||||
.nvd3.nv-bullet .nv-marker { stroke: #000; stroke-width: 2px; }
|
||||
.nvd3.nv-bullet .nv-markerTriangle { stroke: #000; fill: #fff; stroke-width: 1.5px; }
|
||||
.nvd3.nv-bullet .nv-tick line { stroke: #666; stroke-width: .5px; }
|
||||
.nvd3.nv-bullet .nv-range.nv-s0 { fill: #eee; }
|
||||
.nvd3.nv-bullet .nv-range.nv-s1 { fill: #ddd; }
|
||||
.nvd3.nv-bullet .nv-range.nv-s2 { fill: #ccc; }
|
||||
.nvd3.nv-bullet .nv-title { font-size: 14px; font-weight: bold; }
|
||||
.nvd3.nv-bullet .nv-subtitle { fill: #999; }
|
||||
|
||||
|
||||
.nvd3.nv-bullet .nv-range {
|
||||
fill: #bababa;
|
||||
fill-opacity: .4;
|
||||
}
|
||||
.nvd3.nv-bullet .nv-range:hover {
|
||||
fill-opacity: .7;
|
||||
}
|
||||
|
||||
.nvd3.nv-candlestickBar .nv-ticks .nv-tick {
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.nvd3.nv-candlestickBar .nv-ticks .nv-tick.hover {
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
.nvd3.nv-candlestickBar .nv-ticks .nv-tick.positive rect {
|
||||
stroke: #2ca02c;
|
||||
fill: #2ca02c;
|
||||
}
|
||||
|
||||
.nvd3.nv-candlestickBar .nv-ticks .nv-tick.negative rect {
|
||||
stroke: #d62728;
|
||||
fill: #d62728;
|
||||
}
|
||||
|
||||
.with-transitions .nv-candlestickBar .nv-ticks .nv-tick {
|
||||
transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
|
||||
-moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
|
||||
-webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
|
||||
|
||||
}
|
||||
|
||||
.nvd3.nv-candlestickBar .nv-ticks line {
|
||||
stroke: #333;
|
||||
}
|
||||
|
||||
|
||||
.nvd3 .nv-legend .nv-disabled rect {
|
||||
/*fill-opacity: 0;*/
|
||||
}
|
||||
|
||||
.nvd3 .nv-check-box .nv-box {
|
||||
fill-opacity:0;
|
||||
stroke-width:2;
|
||||
}
|
||||
|
||||
.nvd3 .nv-check-box .nv-check {
|
||||
fill-opacity:0;
|
||||
stroke-width:4;
|
||||
}
|
||||
|
||||
.nvd3 .nv-series.nv-disabled .nv-check-box .nv-check {
|
||||
fill-opacity:0;
|
||||
stroke-opacity:0;
|
||||
}
|
||||
|
||||
.nvd3 .nv-controlsWrap .nv-legend .nv-check-box .nv-check {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* line plus bar */
|
||||
.nvd3.nv-linePlusBar .nv-bar rect {
|
||||
fill-opacity: .75;
|
||||
}
|
||||
|
||||
.nvd3.nv-linePlusBar .nv-bar rect:hover {
|
||||
fill-opacity: 1;
|
||||
}
|
||||
.nvd3 .nv-groups path.nv-line {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.nvd3 .nv-groups path.nv-area {
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point {
|
||||
fill-opacity: 0;
|
||||
stroke-opacity: 0;
|
||||
}
|
||||
|
||||
.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point {
|
||||
fill-opacity: .5 !important;
|
||||
stroke-opacity: .5 !important;
|
||||
}
|
||||
|
||||
|
||||
.with-transitions .nvd3 .nv-groups .nv-point {
|
||||
transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
|
||||
-moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
|
||||
-webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
|
||||
|
||||
}
|
||||
|
||||
.nvd3.nv-scatter .nv-groups .nv-point.hover,
|
||||
.nvd3 .nv-groups .nv-point.hover {
|
||||
stroke-width: 7px;
|
||||
fill-opacity: .95 !important;
|
||||
stroke-opacity: .95 !important;
|
||||
}
|
||||
|
||||
|
||||
.nvd3 .nv-point-paths path {
|
||||
stroke: #aaa;
|
||||
stroke-opacity: 0;
|
||||
fill: #eee;
|
||||
fill-opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.nvd3 .nv-indexLine {
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
/********************
|
||||
* SVG CSS
|
||||
*/
|
||||
|
||||
/********************
|
||||
Default CSS for an svg element nvd3 used
|
||||
*/
|
||||
svg.nvd3-svg {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
display: block;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
/********************
|
||||
Box shadow and border radius styling
|
||||
*/
|
||||
.nvtooltip.with-3d-shadow, .with-3d-shadow .nvtooltip {
|
||||
-moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
-webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
|
||||
.nvd3 text {
|
||||
font: normal 12px Arial;
|
||||
}
|
||||
|
||||
.nvd3 .title {
|
||||
font: bold 14px Arial;
|
||||
}
|
||||
|
||||
.nvd3 .nv-background {
|
||||
fill: white;
|
||||
fill-opacity: 0;
|
||||
}
|
||||
|
||||
.nvd3.nv-noData {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/**********
|
||||
* Brush
|
||||
*/
|
||||
|
||||
.nv-brush .extent {
|
||||
fill-opacity: .125;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
.nv-brush .resize path {
|
||||
fill: #eee;
|
||||
stroke: #666;
|
||||
}
|
||||
|
||||
|
||||
/**********
|
||||
* Legend
|
||||
*/
|
||||
|
||||
.nvd3 .nv-legend .nv-series {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nvd3 .nv-legend .nv-disabled circle {
|
||||
fill-opacity: 0;
|
||||
}
|
||||
|
||||
/* focus */
|
||||
.nvd3 .nv-brush .extent {
|
||||
fill-opacity: 0 !important;
|
||||
}
|
||||
|
||||
.nvd3 .nv-brushBackground rect {
|
||||
stroke: #000;
|
||||
stroke-width: .4;
|
||||
fill: #fff;
|
||||
fill-opacity: .7;
|
||||
}
|
||||
|
||||
|
||||
.nvd3.nv-ohlcBar .nv-ticks .nv-tick {
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover {
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
.nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive {
|
||||
stroke: #2ca02c;
|
||||
}
|
||||
|
||||
.nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative {
|
||||
stroke: #d62728;
|
||||
}
|
||||
|
||||
|
||||
.nvd3 .background path {
|
||||
fill: none;
|
||||
stroke: #EEE;
|
||||
stroke-opacity: .4;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
.nvd3 .foreground path {
|
||||
fill: none;
|
||||
stroke-opacity: .7;
|
||||
}
|
||||
|
||||
.nvd3 .nv-parallelCoordinates-brush .extent
|
||||
{
|
||||
fill: #fff;
|
||||
fill-opacity: .6;
|
||||
stroke: gray;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
.nvd3 .nv-parallelCoordinates .hover {
|
||||
fill-opacity: 1;
|
||||
stroke-width: 3px;
|
||||
}
|
||||
|
||||
|
||||
.nvd3 .missingValuesline line {
|
||||
fill: none;
|
||||
stroke: black;
|
||||
stroke-width: 1;
|
||||
stroke-opacity: 1;
|
||||
stroke-dasharray: 5, 5;
|
||||
}
|
||||
.nvd3.nv-pie path {
|
||||
stroke-opacity: 0;
|
||||
transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
|
||||
-moz-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
|
||||
-webkit-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
|
||||
|
||||
}
|
||||
|
||||
.nvd3.nv-pie .nv-pie-title {
|
||||
font-size: 24px;
|
||||
fill: rgba(19, 196, 249, 0.59);
|
||||
}
|
||||
|
||||
.nvd3.nv-pie .nv-slice text {
|
||||
stroke: #000;
|
||||
stroke-width: 0;
|
||||
}
|
||||
|
||||
.nvd3.nv-pie path {
|
||||
stroke: #fff;
|
||||
stroke-width: 1px;
|
||||
stroke-opacity: 1;
|
||||
}
|
||||
|
||||
.nvd3.nv-pie .hover path {
|
||||
fill-opacity: .7;
|
||||
}
|
||||
.nvd3.nv-pie .nv-label {
|
||||
pointer-events: none;
|
||||
}
|
||||
.nvd3.nv-pie .nv-label rect {
|
||||
fill-opacity: 0;
|
||||
stroke-opacity: 0;
|
||||
}
|
||||
|
||||
/* scatter */
|
||||
.nvd3 .nv-groups .nv-point.hover {
|
||||
stroke-width: 20px;
|
||||
stroke-opacity: .5;
|
||||
}
|
||||
|
||||
.nvd3 .nv-scatter .nv-point.hover {
|
||||
fill-opacity: 1;
|
||||
}
|
||||
.nv-noninteractive {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.nv-distx, .nv-disty {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* sparkline */
|
||||
.nvd3.nv-sparkline path {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.nvd3.nv-sparklineplus g.nv-hoverValue {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.nvd3.nv-sparklineplus .nv-hoverValue line {
|
||||
stroke: #333;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
.nvd3.nv-sparklineplus,
|
||||
.nvd3.nv-sparklineplus g {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.nvd3 .nv-hoverArea {
|
||||
fill-opacity: 0;
|
||||
stroke-opacity: 0;
|
||||
}
|
||||
|
||||
.nvd3.nv-sparklineplus .nv-xValue,
|
||||
.nvd3.nv-sparklineplus .nv-yValue {
|
||||
stroke-width: 0;
|
||||
font-size: .9em;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.nvd3.nv-sparklineplus .nv-yValue {
|
||||
stroke: #f66;
|
||||
}
|
||||
|
||||
.nvd3.nv-sparklineplus .nv-maxValue {
|
||||
stroke: #2ca02c;
|
||||
fill: #2ca02c;
|
||||
}
|
||||
|
||||
.nvd3.nv-sparklineplus .nv-minValue {
|
||||
stroke: #d62728;
|
||||
fill: #d62728;
|
||||
}
|
||||
|
||||
.nvd3.nv-sparklineplus .nv-currentValue {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
/* stacked area */
|
||||
.nvd3.nv-stackedarea path.nv-area {
|
||||
fill-opacity: .7;
|
||||
stroke-opacity: 0;
|
||||
transition: fill-opacity 250ms linear, stroke-opacity 250ms linear;
|
||||
-moz-transition: fill-opacity 250ms linear, stroke-opacity 250ms linear;
|
||||
-webkit-transition: fill-opacity 250ms linear, stroke-opacity 250ms linear;
|
||||
}
|
||||
|
||||
.nvd3.nv-stackedarea path.nv-area.hover {
|
||||
fill-opacity: .9;
|
||||
}
|
||||
|
||||
|
||||
.nvd3.nv-stackedarea .nv-groups .nv-point {
|
||||
stroke-opacity: 0;
|
||||
fill-opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
.nvtooltip {
|
||||
position: absolute;
|
||||
background-color: rgba(255,255,255,1.0);
|
||||
color: rgba(0,0,0,1.0);
|
||||
padding: 1px;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
z-index: 10000;
|
||||
display: block;
|
||||
|
||||
font-family: Arial;
|
||||
font-size: 11px;
|
||||
text-align: left;
|
||||
pointer-events: none;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.nvtooltip {
|
||||
background: rgba(255,255,255, 0.8);
|
||||
border: 1px solid rgba(0,0,0,0.5);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/*Give tooltips that old fade in transition by
|
||||
putting a "with-transitions" class on the container div.
|
||||
*/
|
||||
.nvtooltip.with-transitions, .with-transitions .nvtooltip {
|
||||
transition: opacity 50ms linear;
|
||||
-moz-transition: opacity 50ms linear;
|
||||
-webkit-transition: opacity 50ms linear;
|
||||
|
||||
transition-delay: 200ms;
|
||||
-moz-transition-delay: 200ms;
|
||||
-webkit-transition-delay: 200ms;
|
||||
}
|
||||
|
||||
.nvtooltip.x-nvtooltip,
|
||||
.nvtooltip.y-nvtooltip {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.nvtooltip h3 {
|
||||
margin: 0;
|
||||
padding: 4px 14px;
|
||||
line-height: 18px;
|
||||
font-weight: normal;
|
||||
background-color: rgba(247,247,247,0.75);
|
||||
color: rgba(0,0,0,1.0);
|
||||
text-align: center;
|
||||
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
|
||||
-webkit-border-radius: 5px 5px 0 0;
|
||||
-moz-border-radius: 5px 5px 0 0;
|
||||
border-radius: 5px 5px 0 0;
|
||||
}
|
||||
|
||||
.nvtooltip p {
|
||||
margin: 0;
|
||||
padding: 5px 14px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nvtooltip span {
|
||||
display: inline-block;
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
.nvtooltip table {
|
||||
margin: 6px;
|
||||
border-spacing:0;
|
||||
}
|
||||
|
||||
|
||||
.nvtooltip table td {
|
||||
padding: 2px 9px 2px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.nvtooltip table td.key {
|
||||
font-weight:normal;
|
||||
}
|
||||
.nvtooltip table td.value {
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nvtooltip table tr.highlight td {
|
||||
padding: 1px 9px 1px 0;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 4px;
|
||||
border-top-style: solid;
|
||||
border-top-width: 4px;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.nvtooltip table td.legend-color-guide div {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.nvtooltip table td.legend-color-guide div {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
.nvtooltip .footer {
|
||||
padding: 3px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nvtooltip-pending-removal {
|
||||
pointer-events: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/****
|
||||
Interactive Layer
|
||||
*/
|
||||
.nvd3 .nv-interactiveGuideLine {
|
||||
pointer-events:none;
|
||||
}
|
||||
.nvd3 line.nv-guideline {
|
||||
stroke: #ccc;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -123,7 +123,7 @@
|
|||
{% endif %}
|
||||
</h3>
|
||||
<hr/>
|
||||
<div class="viz" style="height: 600px;">
|
||||
<div class="viz" style="height: 700px;">
|
||||
{% block viz_html %}
|
||||
{% if viz.error_msg %}
|
||||
<div class="alert alert-danger">{{ viz.error_msg }}</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
{% macro viz_html(viz) %}
|
||||
<div id="{{ viz.token }}" style="height:100%; width: 100%">
|
||||
<img src="{{ url_for("static", filename="loading.gif") }}" class="loading">
|
||||
<div class="chart" style="height:100%; width: 100%"></div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro viz_js(viz) %}
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
function UTC(dttm){
|
||||
return v = new Date(dttm.getUTCFullYear(), dttm.getUTCMonth(), dttm.getUTCDate(), dttm.getUTCHours(), dttm.getUTCMinutes(), dttm.getUTCSeconds());
|
||||
}
|
||||
var tickMultiFormat = d3.time.format.multi([
|
||||
[".%L", function(d) { return d.getMilliseconds(); }],
|
||||
[":%S", function(d) { return d.getSeconds(); }],
|
||||
["%I:%M", function(d) { return d.getMinutes(); }],
|
||||
["%I %p", function(d) { return d.getHours(); }],
|
||||
["%a %d", function(d) { return d.getDay() && d.getDate() != 1; }],
|
||||
["%b %d", function(d) { return d.getDate() != 1; }],
|
||||
["%B", function(d) { return d.getMonth(); }],
|
||||
["%Y", function() { return true; }]
|
||||
]);
|
||||
colors = [
|
||||
"#FF5A5F", "#007A87", "#7B0051", "#00D1C1", "#8CE071", "#FFB400",
|
||||
"#FFAA91", "#B4A76C", "#9CA299", "#565A5C"
|
||||
];
|
||||
var token = d3.select("#{{ viz.token }}");
|
||||
var jtoken = $("#{{ viz.token }}");
|
||||
var loading = $("#{{ viz.token }}").find("img.loading");
|
||||
var chart = $("#{{ viz.token }}").find("div.chart");
|
||||
var refresh = function(){
|
||||
chart.hide();
|
||||
loading.show();
|
||||
var url = "{{ viz.get_url(json="true")|safe }}";
|
||||
$.getJSON(url, function(data){
|
||||
nv.addGraph(function() {
|
||||
{% if viz.chart_type == 'nvd3_line' %}
|
||||
{% if viz.args.show_brush == 'y' %}
|
||||
var chart = nv.models.lineWithFocusChart()
|
||||
var xext = chart.xAxis.scale().domain();
|
||||
chart
|
||||
.x2Axis
|
||||
.tickFormat(function (d) {return tickMultiFormat(UTC(new Date(d))); })
|
||||
.tickValues([]);
|
||||
{% elif viz.chart_type == 'nvd3_line' %}
|
||||
var chart = nv.models.lineChart()
|
||||
{% endif %}
|
||||
|
||||
chart.xScale(d3.time.scale());
|
||||
chart.xAxis
|
||||
.showMaxMin(false)
|
||||
.tickFormat(function (d) {return tickMultiFormat(new Date(d)); });
|
||||
chart.showLegend({{ "{}".format(viz.args.show_legend=='y')|lower }});
|
||||
|
||||
{% elif viz.chart_type == 'nvd3_bar' %}
|
||||
var chart = nv.models.multiBarChart()
|
||||
.showControls(true) //Allow user to switch between 'Grouped' and 'Stacked' mode.
|
||||
.groupSpacing(0.1); //Distance between each group of bars.
|
||||
|
||||
chart.xAxis
|
||||
.showMaxMin(false)
|
||||
.tickFormat(function (d) {return tickMultiFormat(UTC(new Date(d))); });
|
||||
{% endif %}
|
||||
chart.yAxis.tickFormat(d3.format('.3s'));
|
||||
{% if viz.chart_type == "nvd3_line" and viz.args.rich_tooltip == 'y' %}
|
||||
chart.useInteractiveGuideline(true);
|
||||
{% endif %}
|
||||
{% if viz.args.y_axis_zero == 'y' %}
|
||||
chart.forceY([0, 1]);
|
||||
{% elif viz.args.y_log_scale == 'y' %}
|
||||
chart.yScale(d3.scale.log());
|
||||
{% endif %}
|
||||
|
||||
|
||||
token.select('.chart').append("svg")
|
||||
.datum(data)
|
||||
.transition().duration(500)
|
||||
.call(chart);
|
||||
|
||||
return chart;
|
||||
});
|
||||
chart.show();
|
||||
loading.hide();
|
||||
}).fail(function(xhr) {
|
||||
var err = '<div class="alert alert-danger">' + xhr.responseText + '</div>';
|
||||
loading.hide();
|
||||
chart.show();
|
||||
chart.html(err);
|
||||
});
|
||||
};
|
||||
refresh();
|
||||
jtoken.parent().find("a.refresh").click(refresh);
|
||||
});
|
||||
</script>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro viz_css(viz) %}
|
||||
{% endmacro %}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
from datetime import datetime
|
||||
import hashlib
|
||||
from sqlalchemy.types import TypeDecorator, TEXT
|
||||
import json
|
||||
import parsedatetime
|
||||
|
|
@ -79,3 +80,18 @@ class JSONEncodedDict(TypeDecorator):
|
|||
if value is not None:
|
||||
value = json.loads(value)
|
||||
return value
|
||||
|
||||
def color(s):
|
||||
"""
|
||||
Get a consistent color from the same string using a hash function
|
||||
|
||||
>>> color("foo")
|
||||
'#FF5A5F'
|
||||
"""
|
||||
colors = [
|
||||
"#FF5A5F", "#007A87", "#7B0051", "#00D1C1", "#8CE071", "#FFB400",
|
||||
"#FFAA91", "#B4A76C", "#9CA299", "#565A5C"
|
||||
]
|
||||
h = hashlib.md5(s)
|
||||
i = int(h.hexdigest(), 16)
|
||||
return colors[i % len(colors)]
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import uuid
|
|||
|
||||
from flask import flash
|
||||
from markdown import markdown
|
||||
from pandas.io.json import dumps
|
||||
from werkzeug.datastructures import MultiDict
|
||||
from werkzeug.urls import Href
|
||||
import numpy as np
|
||||
|
|
@ -209,6 +210,14 @@ class WordCloudViz(BaseViz):
|
|||
return df.to_json(orient="records")
|
||||
|
||||
|
||||
class NVD3Viz(BaseViz):
|
||||
verbose_name = "Base NVD3 Viz"
|
||||
template = 'panoramix/viz_nvd3.html'
|
||||
chart_kind = 'line'
|
||||
js_files = ['nv.d3.min.js']
|
||||
css_files = ['nv.d3.css']
|
||||
|
||||
|
||||
class HighchartsViz(BaseViz):
|
||||
verbose_name = "Base Highcharts Viz"
|
||||
template = 'panoramix/viz_highcharts.html'
|
||||
|
|
@ -347,6 +356,81 @@ class TimeSeriesViz(HighchartsViz):
|
|||
return chart.json
|
||||
|
||||
|
||||
class NVD3TimeSeriesViz(NVD3Viz):
|
||||
verbose_name = "NVD3 - Time Series - Line Chart"
|
||||
chart_type = "nvd3_line"
|
||||
form_fields = [
|
||||
'viz_type',
|
||||
'granularity', ('since', 'until'),
|
||||
'metrics',
|
||||
'groupby', 'limit',
|
||||
('rolling_type', 'rolling_periods'),
|
||||
('show_brush', 'show_legend'),
|
||||
('rich_tooltip', 'y_axis_zero'),
|
||||
'y_log_scale',
|
||||
]
|
||||
|
||||
def get_df(self):
|
||||
args = self.args
|
||||
df = super(NVD3TimeSeriesViz, self).get_df()
|
||||
metrics = self.metrics
|
||||
df = df.pivot_table(
|
||||
index="timestamp",
|
||||
columns=self.groupby,
|
||||
values=metrics,)
|
||||
|
||||
rolling_periods = args.get("rolling_periods")
|
||||
rolling_type = args.get("rolling_type")
|
||||
if rolling_periods and rolling_type:
|
||||
if rolling_type == 'mean':
|
||||
df = pd.rolling_mean(df, int(rolling_periods))
|
||||
elif rolling_type == 'std':
|
||||
df = pd.rolling_std(df, int(rolling_periods))
|
||||
elif rolling_type == 'sum':
|
||||
df = pd.rolling_sum(df, int(rolling_periods))
|
||||
return df
|
||||
|
||||
def get_json(self):
|
||||
df = self.get_df()
|
||||
series = df.to_dict('series')
|
||||
datas = []
|
||||
for name, ys in series.items():
|
||||
if df[name].dtype.kind not in "biufc":
|
||||
continue
|
||||
|
||||
df.tz_localize(None)
|
||||
df.index.tz_localize(None)
|
||||
df['timestamp'] = pd.to_datetime(df.index, utc=False)
|
||||
if isinstance(name, basestring):
|
||||
series_title = name
|
||||
elif len(self.metrics) > 1:
|
||||
series_title = ", ".join(name)
|
||||
else:
|
||||
series_title = ", ".join(name[1:])
|
||||
d = {
|
||||
"key": series_title,
|
||||
"color": utils.color(series_title),
|
||||
"values": [
|
||||
{'x': ds, 'y': ys[i]}
|
||||
for i, ds in enumerate(df.timestamp)]
|
||||
}
|
||||
datas.append(d)
|
||||
return dumps(datas)
|
||||
|
||||
|
||||
class NVD3TimeSeriesBarViz(NVD3TimeSeriesViz):
|
||||
verbose_name = "NVD3 - Time Series - Bar Chart"
|
||||
chart_type = "nvd3_bar"
|
||||
form_fields = [
|
||||
'viz_type',
|
||||
'granularity', ('since', 'until'),
|
||||
'metrics',
|
||||
'groupby', 'limit',
|
||||
('rolling_type', 'rolling_periods'),
|
||||
'show_legend',
|
||||
]
|
||||
|
||||
|
||||
class TimeSeriesCompareViz(TimeSeriesViz):
|
||||
verbose_name = "Time Series - Percent Change"
|
||||
compare = 'percent'
|
||||
|
|
@ -413,6 +497,8 @@ class DistributionBarViz(DistributionPieViz):
|
|||
|
||||
viz_types = OrderedDict([
|
||||
['table', TableViz],
|
||||
['nvd3_line', NVD3TimeSeriesViz],
|
||||
['nvd3_bar', NVD3TimeSeriesBarViz],
|
||||
['line', TimeSeriesViz],
|
||||
['big_number', BigNumberViz],
|
||||
['compare', TimeSeriesCompareViz],
|
||||
|
|
|
|||
Loading…
Reference in New Issue