aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/tensorboard/components/tf-image-dashboard/tf-image-grid.html
blob: b7787b98c440b4c1415e565eaa5650a203830345 (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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-styles/paper-styles.html">
<link rel="import" href="tf-image-loader.html">
<link rel="import" href="../imports/lodash.html">
<link rel="import" href="../tf-dashboard-common/scrollbar-style.html">

<!--
tf-image-grid creates a grid for examining image data. The columsn correspond
to runs and the rows correspond to tags. Each cell is an image.

Structurally, it makes extensive use of flexbox for layout: it has a top-level
columnar flexbox that contains the topRow (run names) and then a
bottomContainer. The bottomContainer is another columnar flexbox which contains
repeated image-rows. Each image-row is a row flexbox which contains a tag name
cell, and then image cells.

In the future, we should improve on the layout by making the tag names and run names have fixed positions
within the image-grid, so that when you scroll you always have context (e.g. row and column names in a spreadsheet).
For now, it just scrolls.

The image grid provides internal scroll bars (with styling) so that it can be dropped into
a dashboard in a predictable fashion, even though the internal image grid may be enormous.

Room for future improvement:

- Make it obvious when an image didn't load due to the image not existing.
- Find some way to collapse sparse image grids into denser ones (when sparsity
is high)
- Fix column/row names
- Include hook for loading past images (by step/timestamp? or index?)

-->
<dom-module id="tf-image-grid">
  <template>
    <style include="scrollbar-style"></style>
    <div id="fullContainer" class="container scrollbar">
      <div id="topRow" class="container">
        <div class="noshrink" id="paddingCell"></div>
        <template
          is="dom-repeat"
          items="[[_runs]]"
          as="run"
        >
        <div class="run-name-cell noshrink">
          <span>[[run]]</span>
        </div>
      </template>
      </div>
      <div id="bottomContainer" class="container">
        <template
          is="dom-repeat"
          items="[[_tags]]"
          sort
          as="tag"
        >
          <div class="image-row container noshrink">
            <div class="tag-name-cell noshrink">
              <span class="tag-name">[[tag]]</span>
            </div>
            <template
              is="dom-repeat"
              items="[[_runs]]"
              as="run"
            >
              <div class="image-cell noshrink">
                <template is="dom-if" if="[[_exists(run, tag, runToImages.*)]]">
                  <tf-image-loader
                    id="loader"
                    run="[[run]]"
                    tag="[[tag]]"
                    images-generator="[[imagesGenerator]]"
                    individual-image-generator="[[individualImageGenerator]]"
                  >
                  </tf-image-loader>
                </template>
              </div>
            </template>
          </div>
        </template>
      </div>
    </div>
    <style>
      :host {
        display: block;
        height: 100%;
      }
      .container {
        display: flex;
        flex-wrap: nowrap;
      }
      #fullContainer {
        width: 100%;
        height: 100%;
        flex-direction: column;
        padding-top: 20px;
        overflow: scroll;
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
      }
      #topRow {
        flex-direction: row;
      }
      #bottomContainer {
        flex-direction: column;
        height: 100%;
        width: 100%;
      }
      .image-row {
        flex-direction: row;
      }
      .image-cell {
        width: 300px;
        height: 300px;
        border: 1px solid black;
      }
      .tag-name-cell {
        height: 300px;
        width: 300px;
        display:flex;
        flex-direction: column;
        justify-content: center;
      }
      .tag-name {
        word-wrap: break-word;
        text-align: center;
        white-space: nowrap;
      }
      .run-name-cell {
        width: 300px;
        height: 30px;
        text-align: center;
      }
      .noshrink {
        flex-shrink: 0;
      }
      #paddingCell {
        width: 300px;
        height: 30px;
      }
    </style>
  </template>
  <script>
    Polymer({
      is: "tf-image-grid",
      properties: {
        runToImages: Object,
        _tags: {type: Array, computed: "_getTags(runToImages.*)"},
        _runs: {type: Array, computed: "_getRuns(runToImages.*)"},
        imagesGenerator: Function,
        individualImageGenerator: Function,
      },
      _getTags: function(runToImages) {
        return _.chain(runToImages.base).values().flatten().union().value();
      },
      _getRuns(runToImages) {
        var r2i = runToImages.base;
        return _.keys(r2i).filter(function(x) {return r2i[x].length > 0;});
      },
      _exists: function (run, tag, runToImages) {
        runToImages = runToImages.base;
        return runToImages[run].indexOf(tag) !== -1;
      },
    });
  </script>
</dom-module>