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/session colors #400

Merged
merged 30 commits into from
Aug 20, 2024
Merged

Feature/session colors #400

merged 30 commits into from
Aug 20, 2024

Conversation

interim17
Copy link
Contributor

@interim17 interim17 commented Jun 28, 2024

Time Estimate or Size

medium

related website branchs:
fix/update-ssi -> a patch to bring website into alignment with this changeset
feature/color-session -> the end goal for the feature in development

Advances #510 and #511

Problem

On the front end we need to be storing and applying sets of color changes (browser sessions, or re-applying default). Current code assumes one-color-change-at-a-time.

Solution

UIDisplayData is a good existing data structure that conveys a snapshot of agent tree and its colors.

In SelectionStateInfo colorChanges have been replaced by appliedColors of type UIDisplayData

This is more consistent with the other parts of the selection object which serves as a snapshot of the selection state, rather than as a pass-through for a series of changes.

Keeping this change set small. Possible further changes would keep the SelectionInterface entries object in sync with "rendered state"... Might be useful for writing changes out to new files, not needed right now for MVP.

Type of change

  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Copy link

github-actions bot commented Jun 28, 2024

jest coverage report 🧪

Total coverage

Status Category Percentage Covered / Total
🔴 Statements 40.95% 2043/4989
🔴 Branches 43.21% 838/1939
🔴 Functions 36.92% 418/1132
🔴 Lines 41.17% 1956/4751

Status of coverage: 🟢 - ok, 🟡 - slightly more than threshold, 🔴 - under the threshold

Show files with reduced coverage 🔻

Reduced coverage

Status Filename Statements Branches Functions Lines
🔴 index.ts 7.69% 7.25% 5.64% 7.65%
🔴 src/viewport 14.09% 10.52% 13.95% 13.65%
🔴 index.tsx 14.09% 10.52% 13.95% 13.65%
🔴 src/visGeometry 21.76% 22.79% 27.5% 21.63%

Status of coverage: 🟢 - ok, 🟡 - slightly more than threshold, 🔴 - under the threshold

src/index.ts Outdated
@@ -28,6 +28,6 @@ export {
} from "./simularium";
export { compareTimes, loadSimulariumFile } from "./util";
export { DEFAULT_CAMERA_SPEC } from "./constants";
export { AgentData } from "./simularium/types";
export type { AgentData } from "./simularium/types";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

small bug fix folded in here

Copy link
Contributor

Choose a reason for hiding this comment

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

this should be included in the types imports up above and should be exported directly from "./simularium" like the rest of them are. probably should be it's own PR because currently it breaks running the viewer on main

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you, PR here.

Comment on lines 54 to 73
const appliedColors = uiDisplayData.map((agent) => {
const newAgent = { ...agent };
if (agent.name === selectedAgent) {
if (subAgent.includes("")) {
newAgent.color = selectedColor;
}
const newDisplayStates = agent.displayStates.map(
(state: any) => {
if (subAgent.includes(state.id)) {
return {
...state,
color: selectedColor,
};
}
return state;
}
);
newAgent.displayStates = newDisplayStates;
}
return newAgent;
Copy link
Contributor Author

@interim17 interim17 Jul 19, 2024

Choose a reason for hiding this comment

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

Preview of front end work here in the test bed. Instead of passing in a colorChange we send in a uiDisplayData

In pairing w @meganrm we decided to make the front end responsible for generating and storing this state, viewer just renders

Comment on lines 598 to 606
public changeAgentsColor(appliedColors: UIDisplayData): void {
const colorSettings =
this.selectionInterface.getIdsAndColorsFromUIData(appliedColors);
colorSettings.forEach((setting) => {
this.visGeometry.applyColorToAgents(
setting.agentIds,
setting.color
);
});
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This function now takes in a snapshot of all the colors currently applied, rather than processing individual changes one at a time.

@interim17 interim17 marked this pull request as ready for review July 19, 2024 18:11
@interim17 interim17 requested a review from a team as a code owner July 19, 2024 18:11
@interim17 interim17 requested review from meganrm and frasercl and removed request for a team July 19, 2024 18:11
Copy link
Contributor

@meganrm meganrm left a comment

Choose a reason for hiding this comment

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

looks good, I would pull out the AgentData fix into it's own PR and make sure the exports are consistent with how we're exporting all the other types from the system

@interim17
Copy link
Contributor Author

looks good, I would pull out the AgentData fix into it's own PR and make sure the exports are consistent with how we're exporting all the other types from the system

For context for other reviewers, this is done, the fix has been merged into both main and this branch.

Copy link
Contributor

@frasercl frasercl left a comment

Choose a reason for hiding this comment

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

Couple of concerns, none of which I have enough context on to be sure how concerned I should be. Approving to let you merge at your discretion.

Comment on lines 679 to 688
public setColorSelectionInfo = (appliedColors) => {
this.setState({
...this.state,
uiDisplayData: appliedColors,
selectionStateInfo: {
hiddenAgents: this.state.selectionStateInfo.hiddenAgents,
highlightedAgents:
this.state.selectionStateInfo.highlightedAgents,
colorChange: colorChange,
appliedColors: appliedColors,
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting that state is now duplicated here. I don't have quite enough context on why this would be necessary, or whether this change would imply a similar duplication in the actual simularium-website code. But, particularly if it does, I'd ask a couple questions:

  • If these two values got out of sync with each other, would that represent a meaningful UI state or be some sort of error?
  • If it would be an error, could you get by with just one copy? e.g. could everything that's currently being driven by uiDisplayData instead be driven by appliedColors?
  • It looks like both these state fields are related to props on SimulariumViewer (onUiDisplayDataChanged, selectionStateInfo). If the type of one now contains the other, could/should those paths be merged in the viewer?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently no error will throw, but display will be incorrect if these two are out of sync after more than one color selection.

In the website we will be storing two possibilities for color state (so that we can toggle between default and user selections). The onUiDisplayDataChanged callback will set the default value, and the user selections will be stored separately. The UI components and the redux selector for the selectionStateInfo prop will grab the appropriate one without duplicating the state.

Here we could apply the suggestion from your second bullet, removing the uiDisplayData property from viewerState and driving everything with selectionStateInfo.appliedColors, because we only ever track the current state and never re-apply the default. Not duplicating state = good. But we will be slightly less in sync with naming/conventions of website.

In regards to merging the paths related to onUiDisplayDataChanged and selectionStateInfo:
I did this initially, but it created issues. Essentially now onUiDisplayDataChanged is for parsing new trajectories, whereas selectionStateInfo is about for responding to user changes. Unlikely to merge the paths although open to feedback and also maybe in need of renaming/documenting?

@@ -232,7 +232,7 @@ describe("SelectionInterface module", () => {
{ name: "D", tags: [] },
],
hiddenAgents: [],
colorChange: initialColorChanges,
appliedColors: initialAppliedColors,
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't appear to matter to these tests currently, but be careful: these tests are now taking the same copy of initialAppliedColors by reference, and modifications made by one test could be visible to all the others.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated to use spread operator

Comment on lines 599 to 614
appliedColors.forEach((agent) => {
const agentIds = this.selectionInterface.getAgentIdsByNamesAndTags([
{ name: agent.name, tags: [] },
]);
this.visGeometry.applyColorToAgents(
agentIds,
agent.color
);

agent.displayStates.forEach((state) => {
const stateIds =
this.selectionInterface.getAgentIdsByNamesAndTags([
{ name: agent.name, tags: [state.name] },
]);
this.visGeometry.applyColorToAgents(stateIds, state.color);
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Under the hood, applyColorToAgents is calling VisGeometry.updateScene, which looks like it may be expensive. Now that this call is happening in a loop, is there a way to ensure that the update just happens once, at the end of this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes and why not, its cleaner! Also even if updateScene is relatively cheap (cheap enough to get called in every animate loop at least), it might get more expensive in some upcoming work on caching, so I like the idea of minimizing calls where we can.

Comment on lines +1121 to +1130
colorAssignments.forEach((color) => {
const newColorData = this.colorHandler.setColorForAgentTypes(
color.agentIds,
color.color
);
this.renderer.updateColors(
newColorData.numberOfColors,
newColorData.colorArray
);
});
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@meganrm pointing out the most significant change in response to @frasercl feedback since your approval.

Changed applyColorToAgents to receive array of arguments and back changes so there is only one call to updateScene when applying color changes.

@interim17 interim17 merged commit d3fa1a9 into main Aug 20, 2024
6 checks passed
@interim17 interim17 deleted the feature/session-colors branch August 20, 2024 16:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants