Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

17 condition selector #126

Draft
wants to merge 66 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
6279a01
Initializing PR
bbollen23 Oct 8, 2024
d0e2044
Empty Condition Selector.vue file
Luke-Schreiber Oct 8, 2024
2723c79
Empty condition selector as a registered component
Luke-Schreiber Oct 8, 2024
7391444
Condition Selector moved to folder, condition chart component added
Luke-Schreiber Oct 9, 2024
bd42a2e
main.ts changes whoops
Luke-Schreiber Oct 9, 2024
c6de1db
Created layout for condition selector
bbollen23 Oct 9, 2024
8bd762d
Data Loads
Luke-Schreiber Oct 9, 2024
5c962ff
Added dropdown buttons, condition selector store, and added styling f…
bbollen23 Oct 9, 2024
9274206
Creates vgplot (hard-coded size and attributes)
Luke-Schreiber Oct 9, 2024
ad93c35
Added resizing
bbollen23 Oct 9, 2024
c232a2d
Merge branch '17-condition-selector' of https://github.com/visdesignl…
Luke-Schreiber Oct 9, 2024
942b92c
Updated size slightly
bbollen23 Oct 9, 2024
e5e3e9e
Fixed experiment metadata table names, got condition chart working
bbollen23 Oct 10, 2024
7309d3c
vgplot styling (grey under line chart, smoothed lines)
Luke-Schreiber Oct 15, 2024
cb6ec06
Fixed typing on handleTagClick
bbollen23 Oct 15, 2024
ef1a3b4
ConditionChart gets passed 'props' to create charts. Linting issues c…
Luke-Schreiber Oct 15, 2024
36ac5de
refactoring changes
Luke-Schreiber Oct 16, 2024
d509aee
Merge branch '17-condition-selector' of https://github.com/visdesignl…
Luke-Schreiber Oct 16, 2024
8d666e0
Added small readme
bbollen23 Oct 16, 2024
f9aae63
Fixed condition chart not loading on hot reload while maintaining hot…
bbollen23 Oct 16, 2024
f7cc59d
Labels now come from experiment.json file. Fixed hover effects and re…
bbollen23 Oct 16, 2024
5286a17
Made vg plot dynamic based on tags
bbollen23 Oct 16, 2024
5fe2c04
Changed predicate to const
bbollen23 Oct 16, 2024
4ab1208
Fixed condition selector vue not re-rendering during label update.
bbollen23 Oct 16, 2024
05dc8da
Added avg to the Line chart views. Added "duckdb_findings.txt" file f…
bbollen23 Oct 21, 2024
5fddef4
Added mosaic selection store. All mosaic selections now pass through …
bbollen23 Oct 24, 2024
0be46d7
Removed unnecessary imports in PlotSelector.vue
bbollen23 Oct 24, 2024
f1b4129
Removed tags from createChart input.
bbollen23 Oct 24, 2024
e6f3980
Fixed condition chart not properly rendering dynamic tag names.
bbollen23 Oct 24, 2024
fe0b0b7
Added condition chart color scheme based on y-index. Remove unnecessa…
bbollen23 Oct 24, 2024
5be4a11
Adjusted styles and position for condition charts. Uncentered and mad…
bbollen23 Oct 24, 2024
fb28762
Added selection styles for condition chart. Added param to turn opaci…
bbollen23 Oct 24, 2024
89877ad
Moved mosaic selection interactions to watching variables
bbollen23 Oct 25, 2024
eb6e41b
Changed initialization of condition selector to computed variable
bbollen23 Oct 25, 2024
00c41b1
Revmoed unnecessary logs
bbollen23 Oct 28, 2024
7fb1fef
Shaded area of chart colors altered
Luke-Schreiber Oct 29, 2024
80ce2d3
Track Attributes UI (empty, non-functional yet)
Luke-Schreiber Oct 29, 2024
49fc4f9
Removed clearMosaicSource from plot selector vue since unnecessary. R…
bbollen23 Oct 29, 2024
489073c
Added aggregate table creation
bbollen23 Oct 29, 2024
89af358
Added typing for data selections -- defaults to cell. Updated mosaic …
bbollen23 Oct 30, 2024
1bfdecc
Track Attributes Displays 'avg_mass'
Luke-Schreiber Oct 31, 2024
8976fb2
Added error checking for creating aggregate table. Using header trans…
bbollen23 Oct 31, 2024
7c42e19
creates track level attributes
Luke-Schreiber Oct 31, 2024
624b7bc
Added track level selection
bbollen23 Oct 31, 2024
e2beced
Removed mosaic selection store from plotSelector
bbollen23 Oct 31, 2024
2ed2f48
Changed "mosaicSelection" to "cellLevelSelection". Still using "mosai…
bbollen23 Nov 1, 2024
96c8487
Changed "avg_mass" column to "AVG ${mass}". Made plot selector genera…
bbollen23 Nov 1, 2024
85e41cf
Added AVG, SUM, COUNT, MAX, MIN of all headers to aggregate table.
bbollen23 Nov 1, 2024
2e3e0c9
Added median
bbollen23 Nov 1, 2024
711c848
Track Level Attribute Plots are created based on user specified 'attr…
Luke-Schreiber Nov 8, 2024
3336f14
fixed condition chart and filters not rendering when switching experi…
bbollen23 Nov 8, 2024
bff2f0d
Fixed same label condition chart issue, added proper loading to univa…
bbollen23 Nov 9, 2024
8749a77
Selection/Filter Icons match type.
Luke-Schreiber Nov 11, 2024
1051772
Cell Attributes and Track Attributes are both dialog boxes.
Luke-Schreiber Nov 11, 2024
109c222
caps fixed for 'track' and 'cell' strings
Luke-Schreiber Nov 11, 2024
ea5d21e
Refactored & shortened
Luke-Schreiber Nov 11, 2024
63c536e
'delete' dialog for plots. Empty UI.
Luke-Schreiber Nov 11, 2024
33dd6b0
Rick-Click 'delete' implemented
Luke-Schreiber Nov 11, 2024
4ec16b6
Delete Dialog button spacings
Luke-Schreiber Nov 12, 2024
f06d7f3
Fixed opacity on image view geojson layer, testing for selection stor…
bbollen23 Nov 12, 2024
7c30585
Changed selection and filtering to use duckdb aggregate table.
bbollen23 Nov 12, 2024
fa3b99f
Finished selection and filtering linking. Moved attribute plots into …
bbollen23 Nov 24, 2024
bb556fe
Fixed selections not updating range
bbollen23 Nov 24, 2024
5b58ab5
toggleRelativeChart icon color changes
Luke-Schreiber Nov 26, 2024
c45e318
dark mode for dialogs + attribute select menu position fix
Luke-Schreiber Nov 26, 2024
12403e8
Commented out exemplar view
bbollen23 Nov 26, 2024
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
5 changes: 5 additions & 0 deletions apps/client/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ onBeforeMount(() => {
type="basic"
label="Upload"
/>
<l-btn
@click="router.push('/test')"
type="basic"
label="Test"
/>
</q-toolbar>
</q-header>
<GlobalSettingsView></GlobalSettingsView>
Expand Down
36 changes: 35 additions & 1 deletion apps/client/src/components/AggregateLineChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,19 @@ const areaGen = computed(() => {
);
});


const areaGenHighlighted = computed(() => {
return area<AggDataPoint>()
.x((aggPoint) => scaleX.value(aggPoint.time))
.y0((aggPoint) =>
scaleY.value(aggPoint.value + temp.value * aggPoint.count)
)
.y1((aggPoint) =>
scaleY.value(aggPoint.value - temp.value * aggPoint.count)
)
.defined((aggPoint) => aggPoint.highlighted ?? false);
});

const lineGen = computed(() => {
return line<AggDataPoint>()
.x((aggPoint) => scaleX.value(aggPoint.time))
Expand Down Expand Up @@ -522,7 +535,7 @@ const otherUnmuted = computed(() => {
</g>
<g :transform="`translate(${margin.left},${margin.top})`">
<path
:class="`muted agg-line ${globalSettings.normalizedDark}`"
:class="`muted agg-line ${globalSettings.normalizedDark} ${aggLine.filtered ? 'filtered' : ''}`"
v-for="(
aggLine, index
) in aggregateLineChartStore.aggLineDataList.filter(
Expand All @@ -531,6 +544,18 @@ const otherUnmuted = computed(() => {
:key="index"
:d="areaGen(aggLine.data) ?? ''"
></path>
<!-- Path below is for individual cell tracks with highlighted cells. -->
<path
style="stroke-width: 2px;"
:class="`highlighted-line ${globalSettings.normalizedDark}`"
v-for="(
aggLine, index
) in aggregateLineChartStore.aggLineDataList.filter(
(d) => d.muted
)"
:key="'highlighted-' + index"
:d="areaGenHighlighted(aggLine.data) ?? ''"
></path>
</g>
<g :transform="`translate(${margin.left},${margin.top})`">
<path
Expand Down Expand Up @@ -646,6 +671,15 @@ const otherUnmuted = computed(() => {
stroke-width: 1px;
opacity: 0.6;
}

.highlighted.agg-line{
stroke-width:3px;
opacity:1;
}

.filtered.agg-line{
opacity:0 !important;
}
.selected.agg-line {
stroke-width: 4px;
}
Expand Down
64 changes: 55 additions & 9 deletions apps/client/src/components/ImageViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { TripsLayer } from '@deck.gl/geo-layers';
import { format } from 'd3-format';
import colors from '@/util/colors';
import { useConfigStore } from '@/stores/misc/configStore';
import { useMosaicSelectionStore } from '@/stores/dataStores/mosaicSelectionStore';

const cellMetaData = useCellMetaData();
const globalSettings = useGlobalSettings();
Expand All @@ -57,6 +58,9 @@ const { currentLocationMetadata } = storeToRefs(datasetSelectionStore);
const { contrastLimitSlider } = storeToRefs(imageViewerStoreUntrracked);
const eventBusStore = useEventBusStore();
const looneageViewStore = useLooneageViewStore();
const mosaicSelectionStore = useMosaicSelectionStore();
const { highlightedCellIds, unfilteredTrackIds} = storeToRefs(mosaicSelectionStore);

const deckGlContainer = ref(null);
const { width: containerWidth, height: containerHeight } =
useElementSize(deckGlContainer);
Expand All @@ -66,6 +70,23 @@ const contrastLimit = computed<[number, number][]>(() => {
return [[contrastLimitSlider.value.min, contrastLimitSlider.value.max]];
});

const _determineSelectedOrFiltered = (trackId:string) => {

const frame = imageViewerStore.frameNumber;
const location = currentLocationMetadata.value?.id;
let selected = false;
if(frame && location && highlightedCellIds.value){
// Generate Unique String to compare against list
const unique_string = `${trackId}_${frame}_${location}`
selected = highlightedCellIds.value.includes(unique_string)
}

return {
selected,
filtered: unfilteredTrackIds.value ? !(unfilteredTrackIds.value.includes(trackId)) : false
}
}

let deckgl: any | null = null;
onMounted(() => {
deckgl = new Deck({
Expand Down Expand Up @@ -121,7 +142,6 @@ onMounted(() => {
// onLoad: () => console.log('onLoad'),

getTooltip: ({ object }) => {
console.log(object);
if (!object) return null;
let { id, frame } = object.properties;
if (id == null) return null;
Expand Down Expand Up @@ -152,6 +172,8 @@ onMounted(() => {
eventBusStore.emitter.on('resetImageView', resetView);
});



const loader = ref<any | null>(null);
const pixelSource = ref<any | null>(null);
watch(currentLocationMetadata, async () => {
Expand Down Expand Up @@ -218,7 +240,7 @@ function createSegmentationsLayer(): typeof GeoJsonLayer {
),
lineWidthUnits: 'pixels',
id: 'segmentations',
opacity: 0.4,
opacity: 1,
stroked: true,
filled: true,
getFillColor: (info) => {
Expand All @@ -228,6 +250,11 @@ function createSegmentationsLayer(): typeof GeoJsonLayer {
) {
return hoverColorWithAlpha;
}

const { filtered } = _determineSelectedOrFiltered(info.properties?.id?.toString())
if(filtered){
return[0,0,0,255];
}
return [0, 0, 0, 0];
},
getLineColor: (info) => {
Expand All @@ -242,6 +269,15 @@ function createSegmentationsLayer(): typeof GeoJsonLayer {
) {
return colors.hovered.rgb;
}

const {selected,filtered} = _determineSelectedOrFiltered(info.properties?.id?.toString())
if(filtered){
return [0,0,0];
} else {
if(!selected){
return [0,0,0];
}
}
return colors.unselectedBoundary.rgb;
},
getLineWidth: (info) => {
Expand All @@ -257,9 +293,9 @@ function createSegmentationsLayer(): typeof GeoJsonLayer {
onHover: onHover,
onClick: onClick,
updateTriggers: {
getFillColor: dataPointSelectionUntrracked.hoveredTrackId,
getLineColor: dataPointSelection.selectedTrackId,
getLineWidth: dataPointSelection.selectedTrackId,
getFillColor: [dataPointSelectionUntrracked.hoveredTrackId],
getLineColor: [dataPointSelection.selectedTrackId],
getLineWidth: [dataPointSelection.selectedTrackId]
},
});
}
Expand Down Expand Up @@ -453,17 +489,24 @@ function createCenterPointLayer(): ScatterplotLayer {
if (d.trackId === dataPointSelection.selectedTrackId) {
return globalSettings.normalizedSelectedRgb;
}

const { filtered } = _determineSelectedOrFiltered(d.trackId);

if(filtered){
return[0,0,0,0];
}

return [228, 26, 28];
},
getStrokeWidth: 1,
updateTriggers: {
getFillColor: {
selected: dataPointSelection.selectedTrackId,
hovered: dataPointSelectionUntrracked.hoveredTrackId,
selected: [dataPointSelection.selectedTrackId],
hovered: [dataPointSelectionUntrracked.hoveredTrackId],
},
getLineColor: {
selected: dataPointSelection.selectedTrackId,
hovered: dataPointSelectionUntrracked.hoveredTrackId,
selected: [dataPointSelection.selectedTrackId],
hovered: [dataPointSelectionUntrracked.hoveredTrackId],
},
},
});
Expand Down Expand Up @@ -652,6 +695,9 @@ watch(currentTrackArray, renderDeckGL);
watch(dataPointSelection.$state, renderDeckGL);
watch(imageViewerStore.$state, renderDeckGL);
watch(contrastLimitSlider, renderDeckGL);
watch(highlightedCellIds, renderDeckGL);
watch(unfilteredTrackIds, renderDeckGL);


function clearSelection() {
dataPointSelection.selectedTrackId = null;
Expand Down
155 changes: 155 additions & 0 deletions apps/client/src/components/conditionSelector/ConditionChart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<script setup lang="ts">
import { ref, nextTick } from 'vue';
import { useGlobalSettings } from '@/stores/componentStores/globalSettingsStore';
import { useDatasetSelectionStore } from '@/stores/dataStores/datasetSelectionUntrrackedStore';
import { useMosaicSelectionStore } from '@/stores/dataStores/mosaicSelectionStore';
import { useConditionSelectorStore } from '@/stores/componentStores/conditionSelectorStore';

import * as vg from '@uwdata/vgplot';
import { watch } from 'vue';
import { storeToRefs } from 'pinia';

// Props from parent component
// Accept props from the parent component
const props = defineProps<{
tags: [string, string][];
xAxisName: string;
yAxisName: string;
yIndex: number;
selected: boolean;
chartLineWidth:number;
}>();

// Will use soon for dark mode.
const globalSettings = useGlobalSettings();

const datasetSelectionStore = useDatasetSelectionStore();
const { experimentDataInitialized, currentExperimentMetadata } = storeToRefs(
datasetSelectionStore
);
const { conditionChartSelections, $conditionChartYAxisDomain } = useMosaicSelectionStore();
const { chartColorScheme } = useConditionSelectorStore();

// Container for chart.
const chartContainer = ref<HTMLElement | null>(null);
let observer:MutationObserver|null = null;

const isLoading = ref<boolean>(false);

watch(
[experimentDataInitialized, conditionChartSelections, chartContainer],
async ([isInitialized, newConditionChartSelections, newChartContainer]) => {
if (isInitialized && newChartContainer) {
await nextTick(); // Helps with hot reloading. On save, html ref will be temporarily none. This will wait until html has a ref.
const chart = createChart(props.xAxisName, props.yAxisName);

if(chart){
newChartContainer.appendChild(chart);
observer = new MutationObserver((mutationList) => {
for(const mutation of mutationList) {
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
observer?.disconnect();
break;
}
}
})
}

}
},
{ immediate: true, deep: true }
);

// Creates a new set of selections and adds them to an overall list that is updated whenever general cellLevelSelection is updated.
// Returns the "base" and "filtered". Base a constant selection which is never updated. This is only to filter based on the tags. The "filteredSelection" is updated by other general filters (i.e. cellLevelSelection).

// Styles
const lineColor = chartColorScheme[props.yIndex % 6];
const strokeWidth = props.chartLineWidth/2;
const strokeWidthSelected = props.chartLineWidth;

// const $param = vg.Param.value([0,2000])

function createChart(xAxisName: string, yAxisName: string) {
if (chartContainer.value) {
const source = `${props.tags[0][0]}-${props.tags[0][1]}_${props.tags[1][0]}-${props.tags[1][1]}`;
// Creates chart, filtered by the selection that uses the query.
const chart = vg.plot(
// Fills in area under line chart grey (optional)
vg.areaY(
vg.from(
`${currentExperimentMetadata?.value?.name}_composite_experiment_cell_metadata`,
{
filterBy:
conditionChartSelections[source].baseSelection,
}
),
{
x: xAxisName,
y1: 0,
y: vg.avg(yAxisName),
fill: 'grey',
fillOpacity: 0.3,
curve: 'basis',
stroke: null,
}
),
vg.lineY(
vg.from(
`${currentExperimentMetadata?.value?.name}_composite_experiment_cell_metadata`,
{
filterBy:
conditionChartSelections[source].baseSelection,
}
),
{
x: xAxisName,
y: vg.avg(yAxisName),
stroke: lineColor,
strokeWidth: strokeWidth,
curve: 'basis',
opacity: 0.6,
}
),
vg.lineY(
vg.from(
`${currentExperimentMetadata?.value?.name}_composite_experiment_cell_metadata`,
{
filterBy:
conditionChartSelections[source].filteredSelection,
}
),
{
x: xAxisName,
y: vg.avg(yAxisName),
stroke: lineColor,
strokeWidth: strokeWidthSelected,
curve: 'basis',
opacity: 1,
}
),

// Gets rid of axes and margins
vg.axis(false),
// Below would allow us to adjust the yAxis based on all the charts
vg.yDomain($conditionChartYAxisDomain),
vg.margin(0),
// vg.margin(40)
);
return chart;
}
}
</script>

<template>
<div
v-if="isLoading"
style="position:absolute;width:100%;height:100%;flex:1;display:flex;"
class="flex justify-center"
>
<q-spinner/>
</div>
<div ref="chartContainer"></div>
</template>

<style></style>
Loading