understanding_rl_vision/rl_clarity/svelte/attribution_viewer.svelte (298 lines of code) (raw):

<script> import AttributionSelector from './attribution_selector.svelte'; import Screen from './screen.svelte'; import Chart from './chart.svelte'; import { css_multiply } from './css_manipulate.js'; import { json_load } from './json_load.js'; export let trajectory = null; export let subdirs = { trajectories: "trajectories/", attribution: "attribution/", attribution_totals: "attribution_totals/" }; export let images = null; export let metadata = null; export let channel_totals_jsons = null; export let residual_totals_jsons = null; export let totals_metadata = null; export let json_preloaded = {}; export let state; export let attribution_kinds = []; export let initial_attribution_kinds = []; export let action_htmls = null; export let action_groups = null; export let max_duration; export let video_height; export let video_width; export let attribution_weight; export let attribution_or_gradients = "attribution"; export let attribution_residual; export let attribution_policy = null; export let attribution_single_channel = null; export let channel_colors; const shallow_copy_object = function(obj) { if (obj === null) { return null; } else { return Object.assign({}, obj); } }; const shallow_copy_list_of_objects = function(arr){ let result = []; for (let value of arr) { result.push(shallow_copy_object(value)); } return result; }; const append_last_non_null = function(arr, default_value) { let new_value = default_value; for (let index = arr.length - 1; index >= 0; index--) { if (arr[index] !== null) { new_value = arr[index]; break; } } return arr.concat([new_value]); }; attribution_kinds = shallow_copy_list_of_objects(initial_attribution_kinds); /* let attribution_options = (function() { * let attribution_options = []; * for (let kind_index = 0; kind_index < attribution_kinds.length; kind_index++) { * attribution_options.push(shallow_copy_list_of_objects(init.attribution_options)); * } * return attribution_options; * })(); * let add_attribution_kind = function() { * attribution_kinds = append_last_non_null(attribution_kinds, initial_attribution_kinds[0]); * attribution_kinds[attribution_kinds.length - 1] = shallow_copy_object( * attribution_kinds[attribution_kinds.length - 1]); * attribution_options = append_last_non_null(attribution_options, initial_attribution_options); * attribution_options[attribution_options.length - 1] = shallow_copy_list_of_objects( * attribution_options[attribution_options.length - 1]); * }; * let add_attribution_options = function(kind_index) { * let options = attribution_options[kind_index]; * options = append_last_non_null(options, init.attribution_options[0]); * options[options.length - 1] = shallow_copy_object(options[options.length - 1]); * attribution_options[kind_index] = options; * }; */ let attribution_show_trajectory = true; let attribution_abs = false; const new_attribution_options = function(attribution_show_trajectory, attribution_abs, attribution_residual, attribution_single_channel) { let channel = attribution_single_channel === null ? (attribution_residual ? "all" : "prin") : attribution_single_channel; return [{direction: "non", channel: channel, show_trajectory: true}].concat( attribution_abs ? [ {direction: "abs", channel: channel, show_trajectory: attribution_show_trajectory} ] : [ {direction: "pos", channel: channel, show_trajectory: attribution_show_trajectory}, {direction: "neg", channel: channel, show_trajectory: attribution_show_trajectory} ] ); }; let add_attribution_kind = function() { attribution_kinds = append_last_non_null(attribution_kinds, initial_attribution_kinds[0]); attribution_kinds[attribution_kinds.length - 1] = shallow_copy_object( attribution_kinds[attribution_kinds.length - 1]); attribution_options = attribution_options.concat([ new_attribution_options(attribution_show_trajectory, attribution_abs, attribution_residual, attribution_single_channel) ]); }; $: attribution_options = (function() { let attribution_options = []; for (let kind_index = 0; kind_index < attribution_kinds.length; kind_index++) { attribution_options.push( new_attribution_options(attribution_show_trajectory, attribution_abs, attribution_residual, attribution_single_channel) ); } return attribution_options; })(); $: attribution_images = (function() { let attribution_images = []; for (let kind_index = 0; kind_index < attribution_kinds.length; kind_index++) { let attribution_kind = attribution_kinds[kind_index]; if (attribution_kind === null) { attribution_images.push(null); } else { let kind_images = []; for (let options of attribution_options[kind_index]) { if (options === null) { kind_images.push(null); } else { let selected_metadata = Object.assign(Object.assign({}, attribution_kind), options); kind_images.push((function() { for (let image_index = 0; image_index < images.length; image_index++) { let found = true; for (let key in metadata) { if (Object.prototype.hasOwnProperty.call(metadata, key)) { if (metadata[key][image_index] !== selected_metadata[key]) { found = false; } } } if (found) { return images[image_index]; } } return null; })()); } } attribution_images.push(kind_images); } } return attribution_images; })(); const load_attribution_totals = function(totals_jsons, callback, namespace) { if (totals_jsons !== null) { let urls = totals_jsons.map(json => subdirs.attribution_totals + json); json_load(urls, namespace, json_preloaded).then(callback); } return null; }; const get_attribution_totals = function(totals, totals_metadata, attribution_kinds) { let attribution_totals = []; for (let kind_index = 0; kind_index < attribution_kinds.length; kind_index++) { let attribution_kind = attribution_kinds[kind_index]; if (attribution_kind === null || totals == null) { attribution_totals.push(null); } else { let selected_metadata = Object.assign({}, attribution_kind); attribution_totals.push((function() { for (let totals_index = 0; totals_index < totals.length; totals_index++) { let found = true; for (let key in totals_metadata) { if (Object.prototype.hasOwnProperty.call(totals_metadata, key)) { if (totals_metadata[key][totals_index] !== selected_metadata[key]) { found = false; } } } if (found) { return totals[totals_index]; } } return null; })()); } } return attribution_totals; }; $: channel_totals = (function() { load_attribution_totals(channel_totals_jsons, function(totals) { channel_totals = totals; }, "attribution_channel_totals"); return null; })(); $: residual_totals = (function() { load_attribution_totals(residual_totals_jsons, function(totals) { residual_totals = totals; }, "attribution_residual_totals"); return null; })(); $: attribution_channel_totals = get_attribution_totals(channel_totals, totals_metadata, attribution_kinds); $: attribution_residual_totals = get_attribution_totals(residual_totals, totals_metadata, attribution_kinds); </script> <style> th, td { padding: 0.25em; border-bottom: 1px solid gray; text-align: left; vertical-align: top; } </style> <p> <label style="margin-right: 1em;"><input type="checkbox" bind:checked={attribution_show_trajectory}> overlay on observations</label> <label style="margin-right: 1em;"><input type="checkbox" bind:checked={attribution_abs}> combine positive and negative {attribution_or_gradients}</label> <label><input type="checkbox" bind:checked={attribution_residual}> show residual feature</label> </p> <table style="border-collapse: collapse;"> <tr> {#if attribution_policy} <th colspan="1"></th> {/if} <th>Observation</th> {#if attribution_abs} <th>Positive and negative attribution</th> {:else} <th>Positive attribution</th> <th>Negative attribution</th> {/if} </tr> {#each attribution_kinds as attribution_kind, kind_index} {#if attribution_kind !== null} <tr> {#if attribution_policy} <AttributionSelector bind:type={attribution_kind.type} bind:data={attribution_kind.data} action_htmls={action_htmls} action_groups={action_groups} max_width={video_width} /> {/if} {#each attribution_options[kind_index] as options, options_index} {#if options !== null} <td rowspan="{attribution_policy ? 2 : 1}"> <div style="display: inline-block; border: 1px solid gray;"> <Screen image_dir={""} images={[subdirs.trajectories + trajectory + ".png"].concat(options.direction !== "non" ? [subdirs.attribution + attribution_images[kind_index][options_index]] : [])} durations={[max_duration, max_duration]} weights={[options.show_trajectory ? 1 - attribution_weight : 0].concat(options.direction !== "non" ? [attribution_weight] : [])} grayscales={options.direction !== "non" ? [true, false] : [false]} bind:state={state} height={options_index === 0 ? css_multiply(video_height, 7/8) : video_height} width={options_index === 0 ? css_multiply(video_width, 7/8) : video_width} /> </div> <!-- <AttributionOptionsSelector bind:show_trajectory={options.show_trajectory} bind:direction={options.direction} bind:channel={options.channel} attribution_or_gradients={attribution_or_gradients} width={video_width} /> --> {#if options_index === 0} <br> <div style="display: inline-block;"> <Chart values={attribution_channel_totals[kind_index]} colors={channel_colors} extra_values={attribution_residual_totals[kind_index]} disable_extra={!(attribution_residual || attribution_single_channel == "res")} bind:state={state} height={css_multiply(video_height, 1/4)} width={css_multiply(video_width, 7/8)} /> <!-- {attribution_residual ? attribution_residual_totals[kind_index] : null} --> </div> {/if} </td> {/if} {/each} <!-- <td> <button on:click={() => add_attribution_options(kind_index)}>add</button> </td> --> </tr> {#if attribution_policy} <tr> <td colspan="1" style="vertical-align: middle;"> <button on:click={() => {attribution_kinds[kind_index] = null; attribution_options[kind_index] = null;}}> remove row </button> </td> </tr> {/if} {/if} {/each} {#if attribution_policy} <tr> <td colspan="1" style="vertical-align: middle; border-bottom: 0px;"> <button on:click={add_attribution_kind}>add row</button> </td> </tr> {/if} </table>