aboutsummaryrefslogtreecommitdiff
path: root/data/vue
diff options
context:
space:
mode:
authorPaul Oliver <contact@pauloliver.dev>2026-04-24 05:19:57 +0200
committerPaul Oliver <contact@pauloliver.dev>2026-04-28 00:06:26 +0200
commitf7f2d1193758bb9d7a2d467f188cf755c8d5ddc9 (patch)
tree4c8c0f3df3a67204bb0d16670b360bea6518aa81 /data/vue
parent397286c87dc9aa3cba458973bdc65b3f3be14657 (diff)
Removes old data server and cleans up python code
Diffstat (limited to 'data/vue')
-rw-r--r--data/vue/App.vue378
-rw-r--r--data/vue/Plot.vue155
-rw-r--r--data/vue/Section.vue47
3 files changed, 0 insertions, 580 deletions
diff --git a/data/vue/App.vue b/data/vue/App.vue
deleted file mode 100644
index 8bf2959..0000000
--- a/data/vue/App.vue
+++ /dev/null
@@ -1,378 +0,0 @@
-<template>
- <div ref="top_pad"></div>
- <div class="top_bar" ref="top_bar">
- <h1>
- Salis data server »
- <span class="opts_name">
- {{ opts.name }}
- {{ query_in_progress ? '⧖' : '✓' }}
- </span>
- </h1>
- <form @change="on_form_change">
- <span class="nobr">Rows: <input class="input_small" :class="{ input_touched: inputs.rows !== params.rows }" v-model="inputs.rows" /></span><wbr />
- <span class="nobr">nth: <input class="input_small" :class="{ input_touched: inputs.nth !== params.nth }" v-model="inputs.nth" /></span><wbr />
- <span class="nobr">Axis: <select class="input_small" :class="{ input_touched: inputs.axis !== params.axis }" v-model="inputs.axis"><option v-for="axis in axes">{{ axis }}</option></select></span><wbr />
- <span class="nobr">Low: <input :class="{ input_touched: inputs.low !== params.low }" v-model="inputs.low" /></span><wbr />
- <span class="nobr">High: <input :class="{ input_touched: inputs.high !== params.high }" v-model="inputs.high" /></span><wbr />
- <span class="nobr">Left: <input class="input_small" :class="{ input_touched: inputs.left !== params.left }" v-model="inputs.left" /></span><wbr />
- <span class="nobr">Pixels: <input class="input_small" :class="{ input_touched: inputs.pixels !== params.pixels }" v-model="inputs.pixels" /></span><wbr />
- <span class="nobr">Px-pow: <input class="input_small" :class="{ input_touched: inputs.pixel_pow !== params.pixel_pow }" v-model="inputs.pixel_pow" /></span><wbr />
- <span class="form_button" :class="{ form_button_disabled: !form_touched }" @click="reset_inputs">⨯</span><wbr />
- <span class="form_button" :class="{ form_button_disabled: !form_non_default }" @click="restore_inputs">←</span><wbr />
- <span class="form_button" @click="trigger_reload">↓</span>
- </form>
- </div>
- <Section name="Options" visible>
- <table>
- <tr v-for="opt_fmt in opt_fmts">
- <td>{{ opt_fmt[0] }}:</td>
- <td>{{ opt_fmt[2](opts[opt_fmt[1]]) }}</td>
- </tr>
- </table>
- </Section>
- <!-- Render plots after simulation options have been loaded -->
- <div v-if="loaded">
- <Section :name="section" grid ref="plot_sections" :visible="section === 'General'" triggers_reload v-for="(section_plots, section) in plots">
- <Plot :name="name" :section="section" v-for="(_, name) in section_plots" />
- </Section>
- <Section :name="section" grid ref="heatmap_sections" triggers_reload v-for="(section_heatmaps, section) in heatmaps">
- <Plot is_heatmap :name="name" :section="section" v-for="(_, name) in section_heatmaps" />
- </Section>
- </div>
-</template>
-
-<script setup>
-import { onMounted, provide, useTemplateRef, ref, watch } from 'vue'
-
-import Plot from './Plot.vue'
-import Section from './Section.vue'
-
-const root = window.location.href
-const id = v => v
-const hex = v => v !== undefined ? `0x${v.toString(16)}` : ''
-const hex_pow = v => v !== undefined ? `0x${(2 ** v).toString(16)}` : ''
-const disabled = v => v ? 'disabled' : 'enabled'
-
-const opt_fmts = [
- ['Ancestor', 'anc', id],
- ['Architecture', 'arch', id],
- ['Auto-save interval', 'auto_save_pow', hex_pow],
- ['Clones', 'clones', id],
- ['Cores', 'cores', id],
- ['Data push interval', 'data_push_pow', hex_pow],
- ['Mutator flip bit', 'muta_flip', id],
- ['Mutator range', 'muta_pow', hex_pow],
- ['Memory vector size', 'mvec_pow', hex_pow],
- ['Save file compression', 'no_compress', disabled],
- ['Seed', 'seed', hex],
-]
-
-let visible_plot_tables = []
-let visible_heatmap_tables = []
-let query_timeout = null
-let plot_low = 0
-let plot_redraw = false
-let mvec_size = 0
-let reload_triggered = false
-
-const int_max = Number.MAX_SAFE_INTEGER
-const uint32_max = (2 ** 32) - 1
-const hm_max_pixels = 2 ** 11
-
-let defaults = {
- rows: 2000,
- nth: 1,
- axis: 'rowid',
- low: hex(0),
- high: hex(int_max),
- left: hex(0),
- pixels: hex(2 ** 10),
- pixel_pow: hex(0),
-}
-
-const axes = ref(['rowid', 'step'])
-const inputs = ref({ ...defaults })
-const params = ref({ ...defaults })
-const form_touched = ref(false)
-const form_non_default = ref(false)
-
-const opts = ref({})
-const plots = ref({})
-const heatmaps = ref({})
-const loaded = ref(false)
-
-const query_in_progress = ref(false)
-const data = ref([])
-
-const top_pad = useTemplateRef('top_pad')
-const top_bar = useTemplateRef('top_bar')
-const plot_sections = useTemplateRef('plot_sections')
-const heatmap_sections = useTemplateRef('heatmap_sections')
-
-const adjust_top_bar = () => top_pad.value.style.height = `${Math.round(top_bar.value.getBoundingClientRect().height)}px`
-
-const update_visible_tables = () => {
- const plot_section_visibility = plot_sections.value.map(section => section.visible)
- const heatmap_section_visibility = heatmap_sections.value.map(section => section.visible)
- visible_plot_tables = Object.entries(plots.value).filter((_, i) => plot_section_visibility[i]).map((section, _) => [...new Set(Object.entries(section[1]).map(plot => plot[1].table))]).flat()
- visible_heatmap_tables = Object.entries(heatmaps.value).filter((_, i) => heatmap_section_visibility[i]).map((section, _) => [...new Set(Object.entries(section[1]).map(plot => plot[1].table))]).flat()
-}
-
-const sanitize = (field, min, max, fmt, override = null) => {
- if (isNaN(Number(inputs.value[field])) || inputs.value[field] === '' || inputs.value[field] < min || inputs.value[field] >= max) {
- inputs.value[field] = override !== null ? fmt(Number(override)) : defaults[field]
- } else {
- inputs.value[field] = fmt(Number(inputs.value[field]))
- }
-}
-
-const max_pixel_pow = () => Math.floor(Math.log2((mvec_size - Number(inputs.value.left)) / Number(inputs.value.pixels)))
-const check_form_touched = () => form_touched.value = !Object.keys(inputs.value).every(key => inputs.value[key] === params.value[key])
-const check_form_non_default = () => form_non_default.value = !Object.keys(params.value).every(key => params.value[key] === defaults[key])
-
-const on_form_change = () => {
- sanitize('rows', 1, uint32_max, id)
- sanitize('nth', 1, uint32_max, id)
- sanitize('low', 0, int_max, hex)
- sanitize('high', 1, int_max, hex)
-
- if (opts.value.mvec_loop) {
- sanitize('left', 0, uint32_max, hex)
- sanitize('pixels', 1, hm_max_pixels, hex)
- sanitize('pixel_pow', 0, uint32_max, hex)
- } else {
- sanitize('left', 0, mvec_size, hex)
- sanitize('pixels', 1, hm_max_pixels, hex)
- sanitize('pixel_pow', 0, max_pixel_pow(), hex, max_pixel_pow())
- }
-
- check_form_touched()
-}
-
-const trigger_reload = () => {
- reload_triggered = true
- query()
-}
-
-const reset_inputs = () => {
- inputs.value = { ...params.value }
- on_form_change()
-}
-
-const restore_inputs = () => {
- inputs.value = { ...defaults }
- on_form_change()
-}
-
-const query_table = async (table, is_heatmap, high_now) => {
- const url_params = {
- table: table,
- rows: params.value.rows,
- nth: params.value.nth,
- axis: params.value.axis,
- low: plot_low,
- high: high_now,
- is_eva: is_heatmap,
- ...is_heatmap ? {
- left: Number(params.value.left),
- pixels: Number(params.value.pixels),
- pixel_pow: Number(params.value.pixel_pow),
- } : {},
- }
-
- const search_params = new URLSearchParams(url_params)
- const resp_table = await fetch(root + `data?${search_params}`, { method: 'GET' })
- const text_table = await resp_table.text()
-
- return JSON.parse(text_table)
-}
-
-const query = async () => {
- if (query_in_progress.value) return
-
- clearTimeout(query_timeout)
- query_in_progress.value = true
-
- if (reload_triggered) {
- update_visible_tables()
-
- params.value = { ...inputs.value }
- plot_low = Number(params.value.low)
- plot_redraw = true
-
- check_form_touched()
- check_form_non_default()
-
- reload_triggered = false
- }
-
- const high_params = new URLSearchParams({ axis: params.value.axis })
- const resp_high = await fetch(root + `high?${high_params}`, { method: 'GET' })
- const text_high = await resp_high.text()
- const json_high = JSON.parse(text_high)
- const high_max = json_high.high + 1
- const high_val = Number(params.value.high)
- const high_now = high_max < high_val ? high_max : high_val;
-
- const plot_query_results = await Promise.all(visible_plot_tables.map(table => query_table(table, false, high_now)))
- const heatmap_query_results = await Promise.all(visible_heatmap_tables.map(table => query_table(table, true, high_now)))
- const plot_query_values = Object.fromEntries(visible_plot_tables.map((table, i) => [table, plot_query_results[i]]))
- const heatmap_query_values = Object.fromEntries(visible_heatmap_tables.map((table, i) => [table, heatmap_query_results[i]]))
-
- // Keep track of the highest x-axis value fetched so far.
- // Future queries will set this as the minimum, which prevents re-fetching already stored data.
- plot_low = high_now
-
- data.value = { redraw: plot_redraw, plot_values: plot_query_values, heatmap_values: heatmap_query_values }
- plot_redraw = false
-
- query_in_progress.value = false
-
- if (reload_triggered) {
- query()
- } else {
- query_timeout = setTimeout(query, 10000)
- }
-}
-
-const with_big_ints = (_, val, { source }) => {
- if (Number.isInteger(val) && !Number.isSafeInteger(val)) {
- try { return BigInt(source) } catch {}
- }
-
- return val
-}
-
-onMounted(async () => {
- const resp_opts = await fetch(root + 'opts', { method: 'GET' })
- const resp_plots = await fetch(root + 'plots', { method: 'GET' })
- const resp_heatmaps = await fetch(root + 'heatmaps', { method: 'GET' })
-
- opts.value = JSON.parse(await resp_opts.text(), with_big_ints)
- plots.value = JSON.parse(await resp_plots.text())
- heatmaps.value = JSON.parse(await resp_heatmaps.text())
- loaded.value = true
-
- mvec_size = 2 ** opts.value.mvec_pow
- defaults.pixel_pow = hex(max_pixel_pow())
- inputs.value.pixel_pow = defaults.pixel_pow
- params.value.pixel_pow = defaults.pixel_pow
-
- // All tables should include one cycle column for each core.
- // This allows normalizing the plots against each core's cycle count
- // (i.e. making `cycl_#` the plots' x-axis).
- axes.value.push(...Array(opts.value.cores).keys().map(i => `cycl_${i}`))
-})
-
-watch(loaded, _ => {
- window.addEventListener('resize', adjust_top_bar)
-
- adjust_top_bar()
- update_visible_tables()
- query()
-}, { flush: 'post' })
-
-provide('plots', plots)
-provide('heatmaps', heatmaps)
-provide('params', params)
-provide('data', data)
-provide('trigger_reload', trigger_reload)
-</script>
-
-<style>
-html {
- background-color: black;
- color: gray;
- font-family: sans-serif;
-}
-
-h1 {
- font-size: 18px;
- font-weight: 600;
- margin: 8px 0;
-}
-
-input, select {
- background-color: gray;
- border: none;
- color: black;
- font-family: monospace;
- font-size: 12px;
- margin: 0 4px;
- padding: 2px;
- width: 120px;
-}
-
-table {
- border-collapse: collapse;
- border-spacing: 0;
- height: 100%;
- width: 100%;
-}
-
-tr:nth-child(odd) {
- background-color: #111;
-}
-
-td {
- font-family: monospace;
- font-size: 14px;
- margin: 0;
- padding: 0;
-}
-
-.top_bar {
- background-color: #000;
- border-bottom: 1px solid gray;
- left: 0;
- padding: 8px;
- position: fixed;
- top: 0;
- width: 100%;
- z-index: 1;
-}
-
-.opts_name {
- color: #b58900;
- font-weight: normal;
-}
-
-.nobr {
- font-size: 12px;
- line-height: 28px;
- margin-right: 6px;
- white-space: nowrap;
-}
-
-.input_small {
- width: 80px;
-}
-
-.input_touched {
- background-color: #b58900;
-}
-
-.form_button {
- background-color: black;
- border: 1.5px solid #b58900;
- color: #b58900;
- cursor: pointer;
- display: inline-block;
- font-family: monospace;
- font-size: 14px;
- font-weight: bold;
- height: 16px;
- line-height: 16px;
- margin: 0 4px;
- padding: 2px;
- text-align: center;
- width: 16px;
-}
-
-.form_button_disabled {
- border-color: gray;
- color: gray;
- cursor: default;
- opacity: 0.5;
-}
-</style>
diff --git a/data/vue/Plot.vue b/data/vue/Plot.vue
deleted file mode 100644
index edc989d..0000000
--- a/data/vue/Plot.vue
+++ /dev/null
@@ -1,155 +0,0 @@
-<template>
- <div class="plot_container" :class="{ plot_maximized: maximized, plot_minimized: !maximized }" ref="plot_container">
- <div class="plot" ref="plot_ref">
- <button class="plot_button" @click="plot_toggle_maximize">
- {{ maximized ? '-' : '+' }}
- </button>
- </div>
- </div>
-</template>
-
-<script setup>
-import { defineProps, inject, onMounted, ref, useTemplateRef, watch } from 'vue'
-
-const props = defineProps({ is_heatmap: Boolean, section: String, name: String })
-
-const maximized = ref(false)
-
-const plot_ref = useTemplateRef('plot_ref')
-const plot_container = useTemplateRef('plot_container')
-
-const plots = inject('plots')
-const heatmaps = inject('heatmaps')
-const params = inject('params')
-const data = inject('data')
-
-const plot_toggle_maximize = () => {
- maximized.value = !maximized.value
- Plotly.Plots.resize(plot_ref.value)
- document.body.style.overflow = maximized.value ? 'hidden' : 'visible'
-}
-
-const prevent_plotly_buttons_tab_focus = () => {
- const focusableElements = plot_container.value.querySelectorAll('a, button, input, select')
- focusableElements.forEach(elem => elem.setAttribute('tabindex', '-1'))
-}
-
-const heatmap_init = [{ colorscale: 'Electric', type: 'heatmap', x: [], y: [], z: [] }]
-
-const plot_init = () => {
- const plot_config = plots.value[props.section][props.name]
- const plot_defs = { mode: 'lines', line: { width: 1 }, x: [], y: [] }
-
- switch (plot_config.type) {
- case 'lines':
- return Array.from(plot_config.cols, col => ({ ...plot_defs, name: col }))
- case 'stack':
- return Array.from(plot_config.cols, col => ({ ...plot_defs, stackgroup: 'sg', name: col }))
- case 'stack_percent':
- return Array.from(plot_config.cols, col => ({ ...plot_defs, stackgroup: 'sg', groupnorm: 'percent', name: col }))
- }
-}
-
-onMounted(() => {
- Plotly.newPlot(plot_ref.value, props.is_heatmap ? heatmap_init : plot_init(), {
- font: { color: 'gray', family: 'monospace' },
- legend: { maxheight: 100, orientation: 'h' },
- margin: { b: 48, l: 48, r: 48, t: 48 },
- paper_bgcolor: 'black',
- plot_bgcolor: 'black',
- title: { font: { size: 16 }, text: props.name, x: 0, xref: 'paper' },
- xaxis: { gridcolor: '#111', tickfont: { color: 'gray' }, zerolinecolor: 'gray' },
- yaxis: { gridcolor: '#111', tickfont: { color: 'gray' }, zerolinecolor: 'gray' },
- }, {
- displayModeBar: true,
- responsive: true,
- })
-
- prevent_plotly_buttons_tab_focus()
-})
-
-const update_plot = new_data => {
- const plot_config = plots.value[props.section][props.name]
- const cols = plot_config.cols
- const cols_count = cols.length
- const table_data = new_data.plot_values[plot_config.table]
- const traces = [...Array(cols_count).keys()]
- const xs = Array(cols_count).fill(table_data.map(elem => elem[params.value.axis]))
- const ys = cols.map(column => table_data.map(elem => elem[column]))
-
- // Clear traces
- if (new_data.redraw) {
- const restyle = {
- x: Array.from(cols, () => []),
- y: Array.from(cols, () => []),
- }
-
- Plotly.restyle(plot_ref.value, restyle)
- }
-
- Plotly.extendTraces(plot_ref.value, { x: xs, y: ys }, traces, params.value.rows)
-}
-
-const update_heatmap = new_data => {
- const heatmap_config = heatmaps.value[props.section][props.name]
- const table_data = new_data.heatmap_values[heatmap_config.table]
- const ys = [table_data.map(elem => elem[params.value.axis])]
- const zs = [table_data.map(elem => elem.eva_render.split(' ').map(str => Number('0x' + str)))]
-
- if (new_data.redraw) {
- const px_size = Math.pow(2, Number(params.value.pixel_pow))
- const restyle = {
- x: [Array.from(Array(Number(params.value.pixels)).keys()).map(i => Number(params.value.left) + i * px_size)],
- y: [[]],
- z: [[]],
- }
-
- Plotly.restyle(plot_ref.value, restyle)
- }
-
- Plotly.extendTraces(plot_ref.value, { y: ys, z: zs }, [0], params.value.rows)
-}
-
-watch(data, props.is_heatmap ? update_heatmap : update_plot)
-</script>
-
-<style>
-.plot_container {
- background-color: black;
- display: inline-block;
- width: 100%;
-}
-
-.plot_maximized {
- height: 100%;
- left: 0;
- position: fixed;
- top: 0;
- z-index: 999;
-}
-
-.plot_minimized {
- height: 400px;
- position: relative;
- z-index: 0;
-}
-
-.plot_button {
- background-color: black;
- border: 1.5px solid gray;
- color: gray;
- cursor: pointer;
- font-family: monospace;
- font-size: 18px;
- height: 26px;
- padding: 0;
- position: absolute;
- right: 0;
- top: 0;
- width: 26px;
-}
-
-.plot {
- height: 100%;
-}
-</style>
diff --git a/data/vue/Section.vue b/data/vue/Section.vue
deleted file mode 100644
index 7f4d633..0000000
--- a/data/vue/Section.vue
+++ /dev/null
@@ -1,47 +0,0 @@
-<template>
- <h2 class="section_header" @click="section_toggle_visible">
- {{ name }} <span class="section_button">{{ visible ? '-' : '+' }}</span>
- </h2>
- <div :class="{ section_grid: grid }" v-if="visible">
- <slot></slot>
- </div>
-</template>
-
-<script setup>
-import { defineProps, inject, ref } from 'vue'
-
-const props = defineProps({ name: String, grid: Boolean, visible: Boolean, triggers_reload: Boolean })
-const visible = ref(props.visible)
-const trigger_reload = inject('trigger_reload')
-
-const section_toggle_visible = () => {
- visible.value = !visible.value
- if (props.triggers_reload) trigger_reload()
-}
-
-defineExpose({ visible })
-</script>
-
-<style>
-.section_header {
- border-bottom: 1px solid gray;
- cursor: pointer;
- font-size: 16px;
- font-weight: normal;
-}
-
-.section_button {
- font-family: monospace;
-}
-
-.section_grid {
- display: grid;
- grid-template-columns: 1fr 1fr;
-}
-
-@media screen and (max-width: 800px) {
- .section_grid {
- grid-template-columns: 1fr;
- }
-}
-</style>