提交 ed4bb8f7 编写于 作者: C Cassandra Xia 提交者: TensorFlower Gardener

Added tf-storage component for storing TensorBoard URI state and modified...

Added tf-storage component for storing TensorBoard URI state and modified tf-tensorboard.html to use it. Added tf-globals component to hold TensorBoard global variables.
Change: 125489418
上级 488d183e
/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
/* 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.
......@@ -12,6 +12,8 @@ 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.TensorBoard {
/* tslint:disable:no-namespace */
module TF.Globals {
export var TABS = ['events', 'images', 'audio', 'graphs', 'histograms'];
}
<!-- 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.
=============================================================================-->
<dom-module id="tf-globals">
<script src="globals.js"></script>
</dom-module>
/* 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.
==============================================================================*/
/* tslint:disable:no-namespace */
/**
* The Storage Module provides storage for URL parameters, and an API for
* getting and setting TensorBoard's stateful URI.
*
* It generates URI components like: events&runPrefix=train*
* which TensorBoard uses after like localhost:8000/#events&runPrefix=train*
* to store state in the URI.
*/
module TF.URIStorage {
type StringDict = {[key: string]: string};
/**
* A key that users cannot use, since TensorBoard uses this to store info
* about the active tab.
*/
export let TAB = '__tab__';
/**
* Return a string stored in the URI, given a corresonding key.
* Null if not found.
*/
export function getString(key: string): string {
let items = _componentToDict(_readComponent());
return _.isUndefined(items[key]) ? null : items[key];
}
/**
* Store a string in the URI, with a corresponding key.
*/
export function setString(key: string, value: string) {
let items = _componentToDict(_readComponent());
items[key] = value;
_writeComponent(_dictToComponent(items));
}
/**
* Return a number stored in the URI, given a corresponding key.
*/
export function getNumber(key: string): number {
let items = _componentToDict(_readComponent());
return _.isUndefined(items[key]) ? null : +items[key];
}
/**
* Store a number in the URI, with a corresponding key.
*/
export function setNumber(key: string, value: number) {
let items = _componentToDict(_readComponent());
items[key] = '' + value;
_writeComponent(_dictToComponent(items));
}
/**
* Return an object stored in the URI, given a corresponding key.
*/
export function getObject(key: string): Object {
let items = _componentToDict(_readComponent());
return _.isUndefined(items[key]) ? null : JSON.parse(atob(items[key]));
}
/**
* Store an object in the URI, with a corresponding key.
*/
export function setObject(key: string, value: Object) {
let items = _componentToDict(_readComponent());
items[key] = btoa(JSON.stringify(value));
_writeComponent(_dictToComponent(items));
}
/**
* Read component from URI (e.g. returns "events&runPrefix=train*").
*/
function _readComponent(): string { return window.location.hash.slice(1); }
/**
* Write component to URI.
*/
function _writeComponent(component: string) {
window.location.hash = component;
}
/**
* Convert dictionary of strings into a URI Component.
* All key value entries get added as key value pairs in the component,
* with the exception of a key with the TAB value, which if present
* gets prepended to the URI Component string for backwards comptability
* reasons.
*/
function _dictToComponent(items: StringDict): string {
let component = '';
// Add the tab name e.g. 'events', 'images', 'histograms' as a prefix
// for backwards compatbility.
if (items[TAB] !== undefined) {
component += items[TAB];
}
// Join other strings with &key=value notation
let nonTab = _.pairs(items)
.filter(function(pair) { return pair[0] !== TAB; })
.map(function(pair) {
return encodeURIComponent(pair[0]) + '=' +
encodeURIComponent(pair[1]);
})
.join('&');
return nonTab.length > 0 ? (component + '&' + nonTab) : component;
}
/**
* Convert a URI Component into a dictionary of strings.
* Component should consist of key-value pairs joined by a delimiter
* with the exception of the tabName.
* Returns dict consisting of all key-value pairs and
* dict[TAB] = tabName
*/
function _componentToDict(component: string): StringDict {
let items = {} as StringDict;
let tokens = component.split('&');
tokens.forEach(function(token) {
let kv = token.split('=');
// Special backwards compatibility for URI components like #events
if (kv.length === 1 && _.contains(TF.Globals.TABS, kv[0])) {
items[TAB] = kv[0];
} else if (kv.length === 2) {
items[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]);
}
});
return items;
}
}
<!-- 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.
=============================================================================-->
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="../../webcomponentsjs/webcomponents-lite.min.js"></script>
<script src="../../web-component-tester/browser.js"></script>
<link rel="import" href="../../polymer/polymer.html">
<link rel="import" href="../tf-storage.html">
</head>
<body>
<script src="storageTests.js"></script>
</body>
</html>
/* 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.
==============================================================================*/
// tslint:disable-next-line:no-var-keyword
var assert = chai.assert;
/* tslint:disable:no-namespace */
module TF.URIStorage {
describe('URIStorage', function() {
it('get/setString', function() {
setString('key_a', 'hello');
setString('key_b', 'there');
assert.equal('hello', getString('key_a'));
assert.equal('there', getString('key_b'));
assert.equal(null, getString('key_c'));
});
it('get/setNumber', function() {
setNumber('key_a', 12);
setNumber('key_b', 3.4);
assert.equal(12, getNumber('key_a'));
assert.equal(3.4, getNumber('key_b'));
assert.equal(null, getNumber('key_c'));
});
it('get/setObject', function() {
let obj = {'foo': 2.3, 'bar': 'barstr'};
setObject('key_a', obj);
assert.deepEqual(obj, getObject('key_a'));
});
it('get/setWeirdValues', function() {
setNumber('key_a', NaN);
assert.deepEqual(NaN, getNumber('key_a'));
setNumber('key_a', +Infinity);
assert.equal(+Infinity, getNumber('key_a'));
setNumber('key_a', -Infinity);
assert.equal(-Infinity, getNumber('key_a'));
setNumber('key_a', 1 / 3);
assert.equal(1 / 3, getNumber('key_a'));
setNumber('key_a', -0);
assert.equal(-0, getNumber('key_a'));
});
it('set/getTab', function() {
setString(TAB, TF.Globals.TABS[0]);
assert.equal(TF.Globals.TABS[0], getString(TAB));
});
});
}
<!-- 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.
=============================================================================-->
<link rel="import" href="../tf-globals/tf-globals.html">
<dom-module id="tf-storage">
<script src="storage.js"></script>
</dom-module>
......@@ -5,7 +5,7 @@ describe('end-to-end test', () => {
var tabs = (<any>tb.node()).$.tabs;
function testTab(tabIndex: number) {
it(`selecting ${TF.TensorBoard.TABS[tabIndex]} tab`, done => {
it(`selecting ${TF.Globals.TABS[tabIndex]} tab`, done => {
// Every dashboard emits a rendered event when it is done rendering.
tb.on('rendered', () => done());
tabs.set('selected', tabIndex);
......@@ -18,7 +18,7 @@ describe('end-to-end test', () => {
// have failed. Re-selecting the default tab and listening for
// "rendered" event won't work since the content is not re-stamped.
let selected = +tabs.get('selected');
for (let i = 0; i < TF.TensorBoard.TABS.length; i++) {
for (let i = 0; i < TF.Globals.TABS.length; i++) {
if (i !== selected) {
testTab(i);
}
......
......@@ -9,9 +9,9 @@ describe('fast tab switch', () => {
// the images tab wihout waiting for the graph tab to finish
// rendering. Finally, it finishes when the images tab
// has rendered and no errors were thrown.
let eventsTabIndex = TF.TensorBoard.TABS.indexOf('events');
let imagesTabIndex = TF.TensorBoard.TABS.indexOf('images');
let graphTabIndex = TF.TensorBoard.TABS.indexOf('graphs');
let eventsTabIndex = TF.Globals.TABS.indexOf('events');
let imagesTabIndex = TF.Globals.TABS.indexOf('images');
let graphTabIndex = TF.Globals.TABS.indexOf('graphs');
// Listen for when the events tab rendered.
tb.on('rendered', () => {
......
......@@ -27,10 +27,10 @@ describe('tf-tensorboard tests', () => {
setTimeout(function() {
let tabs = tensorboard.$.tabs.getElementsByTagName('paper-tab');
let tabMode = Array.prototype.map.call(tabs, (x) => x.dataMode);
assert.deepEqual(tabMode, TF.TensorBoard.TABS, 'mode is correct');
assert.deepEqual(tabMode, TF.Globals.TABS, 'mode is correct');
let tabText =
Array.prototype.map.call(tabs, (x) => x.innerText.toLowerCase());
assert.deepEqual(tabText, TF.TensorBoard.TABS, 'text is correct');
assert.deepEqual(tabText, TF.Globals.TABS, 'text is correct');
done();
});
});
......@@ -41,7 +41,7 @@ describe('tf-tensorboard tests', () => {
});
describe('non-graph tabs: reloading the selected dashboard', function() {
TF.TensorBoard.TABS.forEach((name, tabIndex) => {
TF.Globals.TABS.forEach((name, tabIndex) => {
if (name === 'graphs') {
return;
}
......@@ -64,7 +64,7 @@ describe('tf-tensorboard tests', () => {
});
it('reload is disabled for graph dashboard', function(done) {
let idx = TF.TensorBoard.TABS.indexOf('graphs');
let idx = TF.Globals.TABS.indexOf('graphs');
assert.notEqual(idx, -1, 'graphs was found');
tensorboard.$.tabs.set('selected', idx);
setTimeout(
......
......@@ -5,6 +5,7 @@
<link rel="import" href="../paper-toolbar/paper-toolbar.html">
<link rel="import" href="../paper-button/paper-button.html">
<link rel="import" href="../paper-header-panel/paper-header-panel.html">
<link rel="import" href="../tf-globals/tf-globals.html">
<link rel="import" href="../tf-event-dashboard/tf-event-dashboard.html">
<link rel="import" href="../tf-histogram-dashboard/tf-histogram-dashboard.html">
<link rel="import" href="../tf-image-dashboard/tf-image-dashboard.html">
......@@ -12,6 +13,7 @@
<link rel="import" href="../tf-graph-dashboard/tf-graph-dashboard.html">
<link rel="import" href="../tf-dashboard-common/tensorboard-color.html">
<link rel="import" href="../tf-backend/tf-backend.html">
<link rel="import" href="../tf-storage/tf-storage.html">
<!--
tf-tensorboard is the frontend entry point for TensorBoard.
......@@ -19,7 +21,6 @@ tf-tensorboard is the frontend entry point for TensorBoard.
It implements a toolbar (via paper-header-panel and paper-toolbar) that
allows the user to toggle between various dashboards.
-->
<script src="tensorboard.js"></script>
<script src="autoReloadBehavior.js"></script>
<dom-module id="tf-tensorboard">
<template>
......@@ -191,13 +192,13 @@ allows the user to toggle between various dashboards.
tabs: {
type: Array,
readOnly: true,
value: TF.TensorBoard.TABS,
value: TF.Globals.TABS,
},
},
_getModeFromIndex: function(modeIndex) {
var mode = this.tabs[modeIndex];
if (!this.noHash) {
window.location.hash = mode;
TF.URIStorage.setString(TF.URIStorage.TAB, this.tabs[0]);
}
return mode;
},
......@@ -233,11 +234,10 @@ allows the user to toggle between various dashboards.
}.bind(this));
},
_getModeFromHash: function() {
// Return the mode as it is stored in the hash.
var tabName = window.location.hash.trim().slice(1);
var tabName = TF.URIStorage.getString(TF.URIStorage.TAB);
var modeIndex = this.tabs.indexOf(tabName);
if (modeIndex == -1 && this.modeIndex == null) {
// Selecting the first tab as default.
// Select the first tab as default.
this.set('modeIndex', 0);
}
if (modeIndex != -1 && modeIndex != this.modeIndex) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册