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

Feature: adds display of tag descriptions and regexp searching for tags #528

Merged
merged 11 commits into from
Mar 18, 2024
68 changes: 58 additions & 10 deletions src/segmentation_display_state/property_map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ export function parseSegmentQuery(
});
continue;
}
if (labels === undefined) {
if (labels === undefined && tagNames.length == 0) {
errors.push({
begin: startIndex,
end: endIndex,
Expand Down Expand Up @@ -778,7 +778,7 @@ export function parseSegmentQuery(
});
continue;
}
if (labels === undefined) {
if (labels === undefined && tagNames.length == 0) {
errors.push({
begin: startIndex,
end: endIndex,
Expand Down Expand Up @@ -806,6 +806,7 @@ export interface TagCount {
tag: string;
tagIndex: number;
count: number;
desc: string;
}

export interface PropertyHistogram {
Expand Down Expand Up @@ -860,7 +861,10 @@ export function executeSegmentQuery(
}
const properties = inlineProperties?.properties;
const totalIds = inlineProperties.ids.length / 2;
const totalTags = db?.tags?.tags?.length || 0;
let indices = makeIndicesArray(totalIds, totalIds);
const showTags = makeIndicesArray(totalTags, totalTags);
showTags.fill(1);
for (let i = 0; i < totalIds; ++i) {
indices[i] = i;
}
Expand All @@ -877,16 +881,54 @@ export function executeSegmentQuery(
}
indices = indices.subarray(0, outIndex);
};
const filterByTagDescriptions = (regexp: RegExp) => {
const tagDescriptions = db!.tags!.tagDescriptions!;
const tags = db!.tags!.tags!;
const matchingTagDescriptions = tagDescriptions
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably be more efficient to just iterate over the tags with a for loop --- then we wouldn't need to create all of these temporary arrays.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think i've addressed this.. it's failing tests for unrelated reasons.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see #544 for python linting error fix

.map((desc, index) => ({ desc, index }))
.filter(({ desc }) => desc.match(regexp) !== null)
.map(({ index }) => index);
const matchingTags = tags
.map((tag, index) => ({ tag, index }))
.filter(({ tag }) => tag.match(regexp) !== null)
.map(({ index }) => index);

// set showTags based on matchingTags
showTags.fill(0);
matchingTagDescriptions.forEach((index) => (showTags[index] = 1));
matchingTags.forEach((index) => (showTags[index] = 1));
};

// Filter by label
if (query.regexp !== undefined || query.prefix !== undefined) {
const values = db!.labels!.values;
const { regexp, prefix } = query;
if (regexp !== undefined) {
filterIndices((index) => values[index].match(regexp) !== null);
if (db!.labels !== undefined) {
console.log("test");
const values = db!.labels!.values;
if (regexp !== undefined) {
filterIndices((index) => values[index].match(regexp) !== null);
}
if (prefix !== undefined) {
console.log("prefix", prefix);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove console.log

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed!

filterIndices((index) => values[index].startsWith(prefix));
}
}
if (prefix !== undefined) {
filterIndices((index) => values[index].startsWith(prefix));
console.log(indices.length);
// if the regular expression returns nothing
// then assudme the user wants to search through the tags
// and/or tag descriptions
if (
(indices.length == 0 && regexp !== undefined) ||
(db!.labels == undefined && regexp != undefined)
) {
console.log("test3");
indices = makeIndicesArray(totalIds, totalIds);
for (let i = 0; i < totalIds; ++i) {
indices[i] = i;
}
filterByTagDescriptions(regexp);
// reset regexp to none so that it doesn't get applied again
query.regexp = undefined;
}
}

Expand Down Expand Up @@ -924,7 +966,6 @@ export function executeSegmentQuery(
const regexp = new RegExp(pattern);
filterIndices((index) => values[index].match(regexp) !== null);
}

let intermediateIndicesMask: IndicesArray | undefined;
let intermediateIndices: IndicesArray | undefined;

Expand Down Expand Up @@ -970,7 +1011,7 @@ export function executeSegmentQuery(
let tagStatistics: TagCount[] = [];
if (tagsProperty !== undefined) {
const tagStatisticsInQuery: TagCount[] = [];
const { tags, values } = tagsProperty;
const { tags, values, tagDescriptions } = tagsProperty;
const tagCounts = new Uint32Array(tags.length);
for (let i = 0, n = indices.length; i < n; ++i) {
const value = values[indices[i]];
Expand All @@ -983,9 +1024,16 @@ export function executeSegmentQuery(
tagIndex < numTags;
++tagIndex
) {
if (showTags[tagIndex] === 0) continue;
const count = tagCounts[tagIndex];
const tag = tags[tagIndex];
const tagCount = { tag, tagIndex, count: tagCounts[tagIndex] };
const tagDesc = tagDescriptions[tagIndex];
const tagCount = {
tag,
tagIndex,
count: tagCounts[tagIndex],
desc: tagDesc,
};
if (query.includeTags.includes(tag) || query.excludeTags.includes(tag)) {
tagStatisticsInQuery.push(tagCount);
} else if (count > 0) {
Expand Down
10 changes: 8 additions & 2 deletions src/ui/segment_list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -990,12 +990,18 @@ function renderTagSummary(
const filterQuery = queryResult.query as FilterQuery;
const tagList = document.createElement("div");
tagList.classList.add("neuroglancer-segment-query-result-tag-list");
for (const { tag, count } of tags) {
for (const { tag, count, desc } of tags) {
const tagElement = document.createElement("div");
tagElement.classList.add("neuroglancer-segment-query-result-tag");
const tagName = document.createElement("span");
tagName.classList.add("neuroglancer-segment-query-result-tag-name");
tagName.textContent = tag;
// if the tag is different than desc, show both
if (tag !== desc && desc !== undefined && desc !== "") {
tagName.textContent = tag + " (" + desc + ")";
} else {
tagName.textContent = tag;
}

tagList.appendChild(tagElement);
const included = filterQuery.includeTags.includes(tag);
const excluded = filterQuery.excludeTags.includes(tag);
Expand Down
Loading