aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/tensorboard/components/tf_dashboard_common/tf-chart-scaffold.html
blob: 9cacb7f5c894fd0c73d56dac5858d883543f981c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<!--
@license
Copyright 2016 The TensorFlow Authors. 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.
-->

<link rel="import" href="../polymer/polymer.html">

<!--
tf-chart-scaffold is responsible for providing data from TensorBoard to charts.
It has the following settable properties:
tag: (required, string) - the name of the tag to load for this chart
visibleSeries: (required, string[]) - the names of the series the chart should
    display.
dataProvider: (required, VZ.ChartHelpers.DataFn) - function that takes (tag,
    run) and returns a promise containing an array of VZ.ChartHelpers.Datum,
    compatible with TF.Backend.Datum.

It exposes the following methods:
chart() - Returns the underlying chart element.
reload() - Reloads the data and sends it to the underlying chart.

This element should have a compatible chart plugin element as it's content. The
plugin is requred to implement two functions:
- setVisibleSeries(names: string[]): a function that receives an array of series
    names as the first parameter, responsible for changing the series currently
    being displayed to only the series in this array.
- setSeriesData(name: string, data: VZ.ChartHelpers.Datum[]): sets the data of
    the series with the given name to the data given in the second parameter.
-->
<dom-module id="tf-chart-scaffold">
  <template>
    <content></content>
    <style>
      :host {
        -webkit-user-select: none;
        -moz-user-select: none;
        display: flex;
        flex-direction: column;
        flex-grow: 1;
        flex-shrink: 1;
        position: relative;
      }
    </style>
  </template>
  <script>
    "use strict";

    Polymer({
      is: "tf-chart-scaffold",
      properties: {
        tag: String,
        dataProvider: Function,
        visibleSeries: Array,
        _attached: {
          type: Boolean,
          value: false
        },

        // Storing the update ID of the previous request for data enables us to determine if a
        // data response is outdated. We rely on an increasing ID instead of timestamp because
        // successive updates often fire within the same millisecond.
        _dataUpdateIdOfLastRequest: Number,
        _nextAvailableDataUpdateId: {
          type: Number,
          value: 1,
        },
      },
      observers: [
        "reload(tag, dataProvider)",
        "_changeSeries(visibleSeries.*)"
      ],
      ready: function() {
        this.fire('ready');
      },
      attached: function() {
        this._attached = true;
        this._changeSeries();
      },
      detached: function() {
        this._attached = false;
      },
      reload: function() {
        if (!this._attached) {
          return;
        }
        else if (!this.dataProvider) {
          throw new Error('tf-chart-scaffold requires a dataProvider.');
        }
        else if (!this.tag) {
          throw new Error('tf-chart-scaffold requires a tag.');
        }

        // TODO(chizeng): At this point, notify effective children that the previous data has been
        // invalidated. For instance, the image dashboard may want to clear its images. Today, the
        // chart scaffold only informs children when the new image URLs response finishes loading.

        const dataUpdateId = this._nextAvailableDataUpdateId++;
        this._dataUpdateIdOfLastRequest = dataUpdateId;

        this.visibleSeries.forEach(function(name) {
          this.dataProvider(this.tag, name).then(function(data) {
            if (dataUpdateId != this._dataUpdateIdOfLastRequest) {
              // This response is outdated. Ignore it.
              // TODO(chizeng): Explore canceling an outdated request before we even receive its
              // response. This involves creating hooks into the request manager and might introduce
              // some complexity that may not be worth it; Tensorboard frankly does not seem
              // bottlenecked by the network (It is often run in fast corp networks or locally.).
              return;
            }
            this.chart().setSeriesData(name, data);
          }.bind(this));
        }.bind(this));
      },
      _changeSeries: function() {
        if (!this._attached) {
           return;
        }
        else if (!this.visibleSeries) {
          throw new Error('tf-chart-scaffold requires a visibleSeries.');
        }

        this.chart().setVisibleSeries(this.visibleSeries);
        this.reload();
      },
      chart: function() {
        var children = this.getEffectiveChildren();
        if (!children.length) {
          throw new Error('tf-chart-scaffold has no children');
        }

        var child = children[0];
        if (!child.setVisibleSeries || !child.setSeriesData) {
          throw new Error("tf-chart-scaffold's content doesn't implement the " +
              "required interface");
        }
        return child;
      }
    });
  </script>
</dom-module>