facets
facets copied to clipboard
Unable to invoke a custom infoRenderer
Hi all, I'm trying to use a custom infoRenderer but even using defaultInfoRenderer in my html fails.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Results</title>
<script>
window.addEventListener('DOMContentLoaded', function() {
var link = document.createElement('link');
link.rel = "import";
//link.href = "https://raw.githubusercontent.com/PAIR-code/facets/master/facets-dist/facets-jupyter.html";
link.href = "facets-jupyter.html"; // Use a local copy.
link.onload = function() {
var dive = document.createElement('facets-dive');
dive.crossOrigin = "anonymous";
dive.data = [ /* Populated with data here */];
var presets = {
"horizontalFacet": "predicted_string",
"horizontalBuckets": 23,
"verticalBuckets": 23,
"colorBy": "gender",
"verticalFacet": "expected_string",
//"infoRenderer": "FacetsDiveInfoCard.audioRenderer", // Error when using my custom infoRenderer
//"infoRenderer": "FacetsDiveInfoCard.defaultInfoRenderer", // Still fails using the defaultInfoRenderer
//"infoRenderer": "defaultInfoRenderer", // Even not qualified it fails
"imageFieldName": "name"};
for (var key in presets) {
if (presets.hasOwnProperty(key))
dive[key] = presets[key];
}
document.body.appendChild(dive);
}
document.head.appendChild(link);
});
</script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/0.7.24/webcomponents-lite.js"></script>
<style>body, html { height: 100%; margin: 0; padding: 0; width: 100%; }</style>
</head>
<body></body>
</html>
Notice that I tried my custom infoRenderer, a qualified defaultInfoRenderer & defaultInfoRenderer, all three failed with a javascript error message in the client's browser aka Chrome.
I must say that I'm new to bazel and typescript. It would be nice to have more detailed instructions on own to write a customInfoRenderer.
Thanks
Hi Samuel,
It looks like you're specifying a string value here:
"infoRenderer": "FacetsDiveInfoCard.audioRenderer",
Instead, remove the quotes and pass in the literal function value. You don't need that function to be a part of any particular object, it can be a free-floating function.
function myAudioRenderer(selectedObject, element) {
// Render selectedObject into the HTML element.
}
// ...
"infoRenderer": myAudioRenderer,
Hope this helps!
Thanks for the quick response!
I should've RTFM more carefully ;) as it is clear that the infoRenderer is not a string.
I wrote a new solution where in the "demo".html I defined a function like you suggested. This seems to me to be a better solution than to recompile your library. Thus, I would suggest that your documentation on how to create a new infoRenderer be that solution.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Kaggle conv results</title>
<!--
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js"></script>
-->
<script src="handlebars-v4.0.11.js"></script>
<script src="confusion_data.json"></script>
<script id="customInfoRenderer-template" type="text/x-handlebars-template">
<div class="customInfoRenderer">
<h1>Info Card</h1>
<div class="body">
<dl>
<dt>expected</dt>
<dd>{{expected}}</dd>
<dt>expected_string</dt>
<dd>{{expected_string}}</dd>
<dt>filename</dt>
<dd>{{filename}}</dd>
<dt>predicted</dt>
<dd>{{predicted}}</dd>
<dt>predicted_string</dt>
<dd>{{predicted_string}}</dd>
</dl>
</div>
<audio controls autoplay>
<source src="{{filename}}" type="audio/wav">
Your browser does not support the audio element.
</audio>
</div>
</script>
<script id="customInfoRenderer" type="text/javascript">
var source = document.getElementById("customInfoRenderer-template").innerHTML;
var template = Handlebars.compile(source);
customInfoRenderer = function(selectedObject, elem) {
elem.innerHTML = template(selectedObject);
}
</script>
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function() {
var link = document.createElement('link');
link.rel = "import";
//link.href = "https://raw.githubusercontent.com/PAIR-code/facets/master/facets-dist/facets-jupyter.html";
link.href = "facets-jupyter.html";
link.onload = function() {
var dive = document.createElement('facets-dive');
dive.crossOrigin = "anonymous";
dive.data = confusion_data;
var presets = {
"horizontalFacet": "predicted_string",
"horizontalBuckets": 23,
"verticalBuckets": 23,
"colorBy": "gender",
"verticalFacet": "expected_string",
"infoRenderer": customInfoRenderer,
"imageFieldName": "predicted_string"};
for (var key in presets) {
if (presets.hasOwnProperty(key))
dive[key] = presets[key];
}
document.body.appendChild(dive);
}
document.head.appendChild(link);
});
</script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/0.7.24/webcomponents-lite.js"></script>
<style>body, html { height: 100%; margin: 0; padding: 0; width: 100%; }</style>
</head>
<body></body>
</html>
Obviously, using handlebars is not necessary.
My answer was getting a bit long, so I decided to make two comments instead.
I was unable to get my other solution to work. Here are the modifications that I've done so far:
diff --git a/facets_dive/components/facets_dive_info_card/BUILD b/facets_dive/components/facets_dive_info_card/BUILD
index 5fd72a41b..e6e1dab82 100644
--- a/facets_dive/components/facets_dive_info_card/BUILD
+++ b/facets_dive/components/facets_dive_info_card/BUILD
@@ -14,6 +14,7 @@ ts_web_library(
path = "/facets-dive/components/facets-dive-info-card",
deps = [
"//facets_dive/lib:info-renderers",
+ "//facets_dive/lib:audio-renderers",
"@org_polymer_paper_card",
"@org_polymer_paper_styles",
"@org_tensorflow_tensorboard//tensorboard/components/tf_imports:polymer",
diff --git a/facets_dive/components/facets_dive_info_card/facets-dive-info-card.html b/facets_dive/components/facets_dive_info_card/
index a21373162..6438b532e 100644
--- a/facets_dive/components/facets_dive_info_card/facets-dive-info-card.html
+++ b/facets_dive/components/facets_dive_info_card/facets-dive-info-card.html
@@ -18,6 +18,7 @@ limitations under the License.
<link rel="import" href="../../../paper-card/paper-card.html">
<link rel="import" href="../../../paper-styles/typography.html">
<link rel="import" href="../../lib/info-renderers.html">
+<link rel="import" href="../../lib/audio-renderers.html">
<dom-module id='facets-dive-info-card'>
<template>
diff --git a/facets_dive/components/facets_dive_info_card/facets-dive-info-card.ts b/facets_dive/components/facets_dive_info_card/fa
index a1c4772b4..bb4171a91 100644
--- a/facets_dive/components/facets_dive_info_card/facets-dive-info-card.ts
+++ b/facets_dive/components/facets_dive_info_card/facets-dive-info-card.ts
@@ -16,6 +16,7 @@
*/
import {defaultInfoRenderer} from '../../lib/info-renderers';
+import {audioRenderer} from '../../lib/audio-renderers';
export interface FacetsDiveInfoCard extends Element {
/**
diff --git a/facets_dive/lib/BUILD b/facets_dive/lib/BUILD
index 13a05be86..04e12fa59 100644
--- a/facets_dive/lib/BUILD
+++ b/facets_dive/lib/BUILD
@@ -55,6 +55,15 @@ ts_web_library(
)
ts_web_library(
+ name = "audio-renderers",
+ srcs = [
+ "audio-renderers.html",
+ "audio-renderers.ts",
+ ],
+ path = "/facets-dive/lib",
+)
+
+ts_web_library(
name = "label",
srcs = [
"label.html",
diff --git a/facets_dive/lib/audio-renderers.html b/facets_dive/lib/audio-renderers.html
new file mode 100644
index 000000000..b44c93812
--- /dev/null
+++ b/facets_dive/lib/audio-renderers.html
@@ -0,0 +1,17 @@
+<!--
+@license
+Copyright 2017 Google Inc.
+
+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.
+-->
+<script src="audio-renderers.js"></script>
diff --git a/facets_dive/lib/audio-renderers.ts b/facets_dive/lib/audio-renderers.ts
new file mode 100644
index 000000000..ecdf2e59d
--- /dev/null
+++ b/facets_dive/lib/audio-renderers.ts
@@ -0,0 +1,45 @@
+/**
+ * @license
+ * Copyright 2017 Google Inc.
+ *
+ * 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.
+ */
+/**
+ * @fileoverview Example implementation of a custom renderer for the
+ * <facets-dive-info-card> component.
+ */
+
+/**
+ * Given an object and a container element to fill, render the data object's
+ * important information to the element.
+ */
+export const audioRenderer = (selectedObject: any, elem: Element) => {
+ const dl = document.createElement('dl');
+ for (const field in selectedObject) {
+ if (!selectedObject.hasOwnProperty(field)) {
+ continue;
+ }
+ const dt = document.createElement('dt');
+ dt.textContent = field;
+ dl.appendChild(dt);
+ const dd = document.createElement('dd');
+ dd.textContent = selectedObject[field];
+ dl.appendChild(dd);
+ }
+ elem.appendChild(dl);
+ const a = document.createElement('audio');
+ a.src = selectedObject['filename'];
+ a.controls = true;
+ a.autoplay = true;
+ elem.appendChild(a);
+};
Okay, not super creative by I simply wanted to perform the quickest hack possible to be able to play sound files.
Then I compiled your library using the following command and got no error.
bazel build facets:facets_jupyter
Looking at bazel-genfiles/facets/facets-jupyter.html, it seems that my audio-renderer is empty and I don't know why that is the case.
<script>//~~WEBPATH~~/facets-dive/lib/info-renderers.js
function oh(a,b){var c=document.createElement("dl"),d;for(d in a)if(a.hasOwnProperty(d)){var e=document.createElement("dt");e.textContent=d;c.appendChild(e);e=document.createElement("dd");e.textContent=a[d];c.appendChild(e)}b.appendChild(c);c=document.createElement("audio");c.src=a.filename;c.controls=!0;c.autoplay=!0;b.appendChild(c)};
</script>
<script>//~~WEBPATH~~/facets-dive/lib/audio-renderers.js
</script>
Looking at bazel-genfiles/facets/facets-jupyter.html, it seems that my audio-renderer is empty and I don't know why that is the case.
The oh()
function in the info-renderers.js
file appears to be the compiled version of your audioRenderers()
method. I'm not sure why the build system left audio-renderers.js
empty, but it looks like the function has been processed.