Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 1 addition & 16 deletions src/components/ChannelListItem.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { useWorkspaceStore } from 'src/stores/workspace';
import { QPopupEdit } from 'quasar';
import { ref, reactive, nextTick } from 'vue';
import { ref } from 'vue';

const props = defineProps<{
id: number;
Expand All @@ -12,22 +12,9 @@ const workspace_store = useWorkspaceStore(props.id)();

const popup = ref<InstanceType<typeof QPopupEdit>>();

const state = reactive({ popup_disabled: true });

// when clicking the edit button, the popup element is enabled
// we then wait for the next tick for the information to propagate
// afterwards we can actually show the popup
async function edit_process_title(): Promise<void> {
enable_popup();
await nextTick();
popup.value?.show();
}
function disable_popup(): void {
state.popup_disabled = true;
}
function enable_popup(): void {
state.popup_disabled = false;
}

async function update_download_buttons(): Promise<void> {
workspace_store.update_all_svg_urls();
Expand All @@ -40,13 +27,11 @@ async function update_download_buttons(): Promise<void> {
<q-item-label lines="1">
{{ workspace_store.channels[channel_id].title }}
<q-popup-edit
:disable="state.popup_disabled"
ref="popup"
v-model="workspace_store.channels[channel_id]._title"
auto-save
v-slot="scope"
@hide="
disable_popup();
update_download_buttons();
"
>
Expand Down
14 changes: 1 addition & 13 deletions src/components/ProcessListItem.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { useWorkspaceStore } from 'src/stores/workspace';
import { QPopupEdit } from 'quasar';
import { ref, reactive, nextTick } from 'vue';
import { ref } from 'vue';
import { color_scheme } from 'src/utils/colors';

const props = defineProps<{
Expand All @@ -13,19 +13,9 @@ const workspace_store = useWorkspaceStore(props.id)();

const popup = ref<InstanceType<typeof QPopupEdit>>();

const state = reactive({ popup_disabled: true });

async function edit_process_title(): Promise<void> {
enable_popup();
await nextTick();
popup.value?.show();
}
function disable_popup(): void {
state.popup_disabled = true;
}
function enable_popup(): void {
state.popup_disabled = false;
}

const color = ref(workspace_store.colors[props.process_name]);

Expand All @@ -44,13 +34,11 @@ async function update_download_buttons(): Promise<void> {
<q-item-label lines="1">
{{ workspace_store.process_titles[process_name] }}
<q-popup-edit
:disable="state.popup_disabled"
ref="popup"
v-model="workspace_store.process_title_index[process_name]"
auto-save
v-slot="scope"
@hide="
disable_popup();
update_download_buttons();
"
>
Expand Down
45 changes: 15 additions & 30 deletions src/components/WorkspaceListItem.vue
Original file line number Diff line number Diff line change
@@ -1,46 +1,31 @@
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue';
import { ref } from 'vue';
import { QPopupEdit } from 'quasar';
import { useWorkspaceStore } from 'src/stores/workspace';

const props = defineProps<{
id: number;
}>();
const props = defineProps<{ id: number }>();

const workspace_store = useWorkspaceStore(props.id)();
const workspaceStore = useWorkspaceStore(props.id)();

const popup = ref<InstanceType<typeof QPopupEdit>>();

const state = reactive({ popup_disabled: true });

async function edit_workspace_name(): Promise<void> {
enable_popup();
await nextTick();
popup.value?.show();
}
function disable_popup(): void {
state.popup_disabled = true;
}
function enable_popup(): void {
state.popup_disabled = false;
const popupRef = ref();
function editWorkspaceName(): void {
popupRef.value?.show();
}
</script>

<template>
<q-item>
<q-item-section>
<div v-if="workspace_store.loading">
<q-skeleton type="text" width="75px"></q-skeleton>
<div v-if="workspaceStore.loading">
<q-skeleton type="text" width="75px" />
</div>
<div v-else>
{{ workspace_store.name }}
{{ workspaceStore.name }}
<q-popup-edit
:disable="state.popup_disabled"
ref="popup"
v-model="workspace_store.name"
v-model="workspaceStore.name"
ref="popupRef"
auto-save
v-slot="scope"
@hide="disable_popup"
>
<q-input
v-model="scope.value"
Expand All @@ -53,15 +38,15 @@ function enable_popup(): void {
</q-item-section>
<q-item-section side top>
<q-btn
:disable="workspace_store.loading"
@click="edit_workspace_name()"
:disable="workspaceStore.loading"
@click="editWorkspaceName()"
icon="edit"
/>
</q-item-section>
<q-item-section side bottom>
<q-btn
:disable="workspace_store.loading"
@click="workspace_store.delete_workspace()"
:disable="workspaceStore.loading"
@click="workspaceStore.delete_workspace()"
icon="delete"
/>
</q-item-section>
Expand Down
2 changes: 1 addition & 1 deletion src/components/WorkspaceLoader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { IAnalysis, IAnalysisOption } from 'src/interfaces';
const storeid_store = useStoreIDStore();

const hepdata_id = ref('');
const analyses = ref([] as IAnalysis[]);
const analyses = ref<IAnalysis[]>([]);
let analyses_to_load = [] as IAnalysisOption[];
const files = ref();
const button_is_disabled = computed(() => {
Expand Down
13 changes: 5 additions & 8 deletions src/components/charts/ModifierStructureChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,11 @@ const legend_height = computed(() => {
});

// pre-compute positions of rects
const x_pos = computed(() => {
// return list of x-positions for the modifiers
return workspace_store.modifier_names.map(
(_, index) => index * size + ylabel_length.value + label_offset
);
});
const x_pos: number[] = workspace_store.modifier_names.map(
(_, index) => index * size + ylabel_length.value + label_offset
);

const y_pos = computed(() => {
const y_pos: number[][] = (() => {
const positions: number[][] = [];
let channel_offset = 0;
for (const channel of workspace_store.channels) {
Expand All @@ -87,7 +84,7 @@ const y_pos = computed(() => {
channel_offset += channel.samples.length * size + padding;
}
return positions;
});
})();

// make interactive
const state = reactive({
Expand Down
14 changes: 4 additions & 10 deletions src/components/charts/NormalizedBarChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,12 @@ const offset =
(bar_height + padding) * workspace_store.channels.length + padding;

// create strings for path of axes
const y_ticks = [
...Array(workspace_store.channels.length)
.fill(0)
.map((_, i) => (i + 0.5) * bar_height + (i + 1) * padding),
];
const y_ticks = Array.from({ length: workspace_store.channels.length }, (_, i) =>
(i + 0.5) * bar_height + (i + 1) * padding
);
const yaxis_path = axis_path(0, 0, offset, y_ticks, false, true);

const x_ticks = [
...Array(number_of_ticks)
.fill(0)
.map((_, i) => i * (x_range / (number_of_ticks - 1))),
];
const x_ticks = Array.from({ length: number_of_ticks }, (_, i) => i * (x_range / (number_of_ticks - 1)));
const xaxis_path = axis_path(0, offset, x_range, x_ticks, true, true);

// the height of the plot should be at least the height of the bars corresponding to the different channels
Expand Down
46 changes: 11 additions & 35 deletions src/components/charts/StackedChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,14 @@ const channel = workspace_store.channels[props.channel_index];

const number_of_bins = channel.samples[0].data.length;

const bins = Array.from({ length: number_of_bins }, (e, i) => i);
const bins = Array.from({ length: number_of_bins }, (_, i) => i);

const maximum = computed(() => {
let max = 0;
for (
let i_bin = 0;
i_bin < channel.stacked_data_per_bin.content.length;
i_bin++
) {
const high_value =
channel.stacked_data_per_bin.content[i_bin][
workspace_store.process_names.length - 1
].high;
if (max < high_value) {
max = high_value;
}
const data_value = channel.stacked_data_per_bin.data[i_bin];
if (max < data_value) {
max = data_value;
}
}
channel.stacked_data_per_bin.content.forEach((binContent, i_bin) => {
const high = binContent[workspace_store.process_names.length - 1].high;
max = Math.max(max, high, channel.stacked_data_per_bin.data[i_bin]);
});
return max;
});

Expand Down Expand Up @@ -90,23 +77,16 @@ const y_ticks = computed(() => {
} else if (max >= 3) {
stepsize = 1;
}
let i = 0;
const ticks = [];
while (i <= max) {
for (let i = 0; i <= max; i+= stepsize) {
ticks.push(i);
i += stepsize;
}
return ticks;
});

const y_tick_positions = computed(() => {
const max = maximum_normalised.value;
let tick_positions = [];
for (const tick of y_ticks.value) {
tick_positions.push(-(300 / max) * tick);
}
return tick_positions;
});
const y_tick_positions = computed(() =>
y_ticks.value.map(tick => -(300 / maximum_normalised.value) * tick)
);

const yaxis_path = axis_path(100, 350, 40, y_tick_positions.value, false, true);
</script>
Expand Down Expand Up @@ -226,14 +206,10 @@ const yaxis_path = axis_path(100, 350, 40, y_tick_positions.value, false, true);
</template>

<style scoped>
rect.isnothighlighted {
fill-opacity: 0.5;
transition: fill-opacity 0.5s ease;
}

rect.isnothighlighted,
path.isnothighlighted {
fill-opacity: 0.5;
transition: fill-opacity 0.5s ease;
transition: fill-opacity 0.5s ease, fill 0.5s ease;
}

text.isnothighlighted {
Expand Down
50 changes: 23 additions & 27 deletions src/core/hepdata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ import { useWorkspaceStore } from 'src/stores/workspace';
import type { IAnalysis, IHEPdataentry, IWorkspace } from 'src/interfaces';
import { Notify } from 'quasar';

type HEPDataFileResponse = {
file_contents: string;
};

async function fetchJson<T>(url: string): Promise<T | null> {
try {
const response = await fetch(url);
return await response.json();
} catch {
return null;
}
}

export async function check_workspaces_on_HEPdata(
hepdata_id: string
): Promise<IAnalysis[]> {
Expand All @@ -12,10 +25,8 @@ export async function check_workspaces_on_HEPdata(
'https://www.hepdata.net/record/ins' +
hepdata_id +
'?format=json&light=true';
let hepdata_entry: IHEPdataentry | null = null;
try {
hepdata_entry = await (await fetch(hepdata_url)).json();
} catch {
const hepdata_entry = await fetchJson<IHEPdataentry>(hepdata_url);
if (!hepdata_entry?.record?.analyses) {
Notify.create({
message:
'Invalid JSON encountered. Are you sure you provided the correct HEPdata ID?',
Expand All @@ -25,52 +36,37 @@ export async function check_workspaces_on_HEPdata(
});
return [];
}
const analyses: IAnalysis[] | undefined = [];
if (hepdata_entry?.record.analyses === undefined) {
return [];
}
for (const analysis of hepdata_entry?.record.analyses) {
if (analysis.type !== 'HistFactory') {
continue;
}
analyses.push({
name: analysis.filename,
url: analysis.analysis,
});
}
if (analyses === undefined || analyses.length === 0) {
const analyses = hepdata_entry.record.analyses
.filter(a => a.type === 'HistFactory')
.map(a => ({ name: a.filename, url: a.analysis }));
if (analyses.length === 0) {
Notify.create({
message:
'No JSON workspaces are available for this HEPData entry. Are you sure you provided the correct HEPdata ID?',
color: 'negative',
icon: 'report_problem',
position: 'top',
});
return [];
}
store_id_store.checking = false;
return analyses;
}

export async function load_workspaces_from_HEPdata(analyses: IAnalysis[]): Promise<void> {
for (const analysis of analyses) {
load_workspace_from_HEPdata(analysis);
}
await Promise.all(analyses.map(load_workspace_from_HEPdata));
}

export async function load_workspace_from_HEPdata_resource(record_id: string): Promise<void> {
const analysis: IAnalysis = {name: 'Resource ID: ' + record_id, url: 'https://www.hepdata.net/record/resource/'+record_id+'?landing_page=true'}
load_workspace_from_HEPdata(analysis);
await load_workspace_from_HEPdata(analysis);
}

export async function load_workspace_from_HEPdata(analysis: IAnalysis): Promise<void> {
const store_id_store = useStoreIDStore();
const id = store_id_store.add_store_with_id();
const workspace_store = useWorkspaceStore(id)();
const response = await (
await fetch(analysis.url.replace('landing_page=true', 'format=json'))
).json()
let workspace = {} as IWorkspace
const response = await fetchJson<HEPDataFileResponse>(analysis.url.replace('landing_page=true', 'format=json'));
let workspace: IWorkspace;
if (response.file_contents === 'Large text file') {
workspace = await (
await fetch(
Expand Down