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/set agent color #325

Merged
merged 36 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
08382d4
handle colorChangeAgents in selectioninterface
interim17 Aug 3, 2023
531897e
apply color changes in viewport
interim17 Aug 3, 2023
37700b7
set color change in visGeometry
interim17 Aug 3, 2023
9eb0c44
implement ui for color change in example viewer
interim17 Aug 3, 2023
f388190
main function setAgentColor and helper functions
interim17 Aug 3, 2023
1479b45
tighten up variable names
interim17 Aug 4, 2023
25c37a8
clean up, rename functions
interim17 Aug 4, 2023
ee6ed4a
rename custom and assigned color props
interim17 Aug 4, 2023
63522b6
add user colors to agentcolors
interim17 Aug 9, 2023
3965da3
update tests, add test for getColorChangeIds
interim17 Aug 9, 2023
4e13fb4
setColors function
interim17 Aug 16, 2023
38962e0
Merge branch 'main' into feature/set-agent-color
interim17 Aug 16, 2023
135ee7b
add tag/subagent selection to example viewer
interim17 Aug 17, 2023
3d61f18
tidy example viewer
interim17 Aug 17, 2023
04ba2d5
tidying viewer
interim17 Aug 17, 2023
38b6fb1
comment out colorMappingSet error
interim17 Aug 17, 2023
29efd27
move color picker out of viewer
meganrm Aug 23, 2023
95cc6f7
allow to add agent color
meganrm Aug 23, 2023
ccc229f
move more of the color change to visGeometry
meganrm Aug 23, 2023
741e934
remove unneeded function
meganrm Aug 23, 2023
e0f0d88
update tests
meganrm Aug 23, 2023
f6eae93
Merge pull request #328 from simularium/feature/set-agent-color-edits
interim17 Aug 24, 2023
9c502b1
update colorChanges typing to array
interim17 Sep 7, 2023
6fa78d2
bug fix restore code to onTrajFileInfo
interim17 Sep 7, 2023
7d33f92
cleanup unused colormapping in VisGeo
interim17 Sep 7, 2023
81ebadd
working updateUiData
interim17 Sep 19, 2023
498752d
send updated uidata to handler
interim17 Sep 20, 2023
16b162a
clean up comments
interim17 Sep 20, 2023
73ad0f5
fix example viewer color change
interim17 Sep 21, 2023
1531bf2
remove unused function
interim17 Sep 22, 2023
33afb92
update tests
interim17 Sep 22, 2023
8ddf9d2
adjust tests to code changes
interim17 Sep 22, 2023
72c38cd
unused import and const -> let
interim17 Sep 25, 2023
a36f698
typedeclarations colorchange and selectionentry
interim17 Oct 5, 2023
71649d0
export types from index
interim17 Oct 5, 2023
ee7b583
remove unnecessary type export
interim17 Oct 5, 2023
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
168 changes: 158 additions & 10 deletions examples/Viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import ConversionForm from "./ConversionForm";
import MetaballSimulator from "./MetaballSimulator";
import { TrajectoryType } from "../src/constants";
import { NetConnectionParams } from "../src/simularium";
import { SelectionEntry } from "../src/simularium/SelectionInterface";

let playbackFile = "TEST_LIVEMODE_API"; //"medyan_paper_M:A_0.675.simularium";
let queryStringFile = "";
Expand Down Expand Up @@ -85,6 +86,12 @@ interface ViewerState {
name: string;
data: ISimulariumFile | null;
} | null;
selectedColor: string;
customColor: string;
assignedColor: string;
selectedAgent: string;
subAgentNames: string[];
selectedSubAgent: string;
}

interface BaseType {
Expand Down Expand Up @@ -139,9 +146,15 @@ const initialState: ViewerState = {
selectionStateInfo: {
highlightedAgents: [],
hiddenAgents: [],
colorChangeAgents: [],
},
filePending: null,
simulariumFile: null,
selectedColor: "",
selectedAgent: "",
customColor: "",
subAgentNames: [],
selectedSubAgent: "",
};

type FrontEndError = typeof FrontEndError;
Expand Down Expand Up @@ -590,6 +603,76 @@ class Viewer extends React.Component<InputParams, ViewerState> {
URL.revokeObjectURL(downloadLink.href);
}

public handleColorSelection = (event) => {
this.setState({ selectedColor: event.target.value });
};

public handleAgentSelection = (event) => {
const value = event.target.value;
this.setState({ selectedAgent: value });
const subAgents = this.getSubAgentsforAgent(value);
if (subAgents) {
this.setState({ subAgentNames: subAgents });
}
};

public handleSubAgentSelection = (event) => {
const value = event.target.value;
this.setState({ selectedSubAgent: value });
};

public getSubAgentsforAgent = (agentName: string) => {
const agent = this.state.uiDisplayData.find(
(element) => element.name === agentName
);
if (!agent) {
throw new Error("No agent found");
return;
}
return agent.displayStates.map((element) => element.id);
};

public assignColorToAgent = () => {
if (!this.state.selectedAgent) {
throw new Error("No agent selected");
return;
} else if (!this.state.selectedColor) {
throw new Error("No color selected");
return;
} else {
const subAgent: string[] = this.state.selectedSubAgent ? [this.state.selectedSubAgent] : [];
const entry: SelectionEntry[] = [{
name: this.state.selectedAgent,
tags: subAgent,
}];
this.setState({
...this.state,
selectionStateInfo: {
...this.state.selectionStateInfo,
colorChangeAgents: entry,
},
assignedColor: this.state.selectedColor,
});
}
};

public receiveNewColorInput = (event) => {
const value = event.target.value;
this.setState({ customColor: value });
};

public addColorToColorArray = (event) => {
const hexColorCodeRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
const color = this.state.customColor;
if (hexColorCodeRegex.test(color)) {
this.setState({
agentColors: [...this.state.agentColors, color] as string[],
});
} else {
alert("Please enter a valid hex color code");
}
};

public render(): JSX.Element {
if (this.state.filePending) {
const fileType = this.state.filePending.type;
Expand Down Expand Up @@ -624,15 +707,33 @@ class Viewer extends React.Component<InputParams, ViewerState> {
<option value="microtubules30_1.h5">MT 30</option>
<option value="endocytosis.simularium">Endocytosis</option>
<option value="pc4covid19.simularium">COVIDLUNG</option>
<option value="nanoparticle_wrapping.simularium">Nanoparticle wrapping</option>
<option value="smoldyn_min1.simularium">Smoldyn min1</option>
<option value="smoldyn_spine.simularium">Smoldyn spine</option>
<option value="medyan_Chandrasekaran_2019_UNI_alphaA_0.1_MA_0.675.simularium">medyan 625</option>
<option value="medyan_Chandrasekaran_2019_UNI_alphaA_0.1_MA_0.0225.simularium">medyan 0225</option>
<option value="springsalad_condensate_formation_Below_Ksp.simularium">springsalad below ksp</option>
<option value="springsalad_condensate_formation_At_Ksp.simularium">springsalad at ksp</option>
<option value="springsalad_condensate_formation_Above_Ksp.simularium">springsalad above ksp</option>
<option value="blood-plasma-1.0.simularium">blood plasma</option>
<option value="nanoparticle_wrapping.simularium">
Nanoparticle wrapping
</option>
<option value="smoldyn_min1.simularium">
Smoldyn min1
</option>
<option value="smoldyn_spine.simularium">
Smoldyn spine
</option>
<option value="medyan_Chandrasekaran_2019_UNI_alphaA_0.1_MA_0.675.simularium">
medyan 625
</option>
<option value="medyan_Chandrasekaran_2019_UNI_alphaA_0.1_MA_0.0225.simularium">
medyan 0225
</option>
<option value="springsalad_condensate_formation_Below_Ksp.simularium">
springsalad below ksp
</option>
<option value="springsalad_condensate_formation_At_Ksp.simularium">
springsalad at ksp
</option>
<option value="springsalad_condensate_formation_Above_Ksp.simularium">
springsalad above ksp
</option>
<option value="blood-plasma-1.0.simularium">
blood plasma
</option>
<option value="TEST_SINGLE_PDB">TEST SINGLE PDB</option>
<option value="TEST_PDB">TEST PDB</option>
<option value="TEST_FIBERS">TEST FIBERS</option>
Expand Down Expand Up @@ -795,7 +896,9 @@ class Viewer extends React.Component<InputParams, ViewerState> {
<br />
<button
onClick={() =>
simulariumController.getMetrics(this.netConnectionSettings)
simulariumController.getMetrics(
this.netConnectionSettings
)
}
>
Get available metrics
Expand Down Expand Up @@ -828,6 +931,50 @@ class Viewer extends React.Component<InputParams, ViewerState> {
Tick interval length:{" "}
{simulariumController.tickIntervalLength}
</span>
<br></br>
<span>Color change agent selections:</span>
<select
id="agentSelect"
onChange={this.handleAgentSelection}
>
<option value="Select Agent"> Select Agent</option>
{this.state.particleTypeNames.map((name) => (
<option value={name}>{name}</option>
))}
</select>
<select
id="subAgentSelect"
onChange={this.handleSubAgentSelection}
>
<option value="Select Sub-Agent"> Select Sub-Agent</option>
{this.state.subAgentNames.map((name) => (
<option value={name}>{name}</option>
))}
</select>
<select
id="colorSelect"
onChange={this.handleColorSelection}
defaultValue={this.state.selectedColor}
style={{ backgroundColor: this.state.selectedColor }}
>
<option value="Select Color"> Select Color</option>
{this.state.agentColors.map((name) => (
<option value={name}>{name}</option>
))}
</select>
<button onClick={this.assignColorToAgent}>
{" "}
Apply Color to Agent
</button>
<input
id="colorAddition"
type="text"
placeholder="add Hex Color"
onChange={this.receiveNewColorInput}
></input>
<button onClick={this.addColorToColorArray}>
Add color to color array
</button>
<div className="viewer-container">
<SimulariumViewer
ref={this.viewerRef}
Expand All @@ -851,6 +998,7 @@ class Viewer extends React.Component<InputParams, ViewerState> {
showPaths={this.state.showPaths}
onError={this.onError}
backgroundColor={[0, 0, 0]}
assignedColor={this.state.assignedColor}
/>
</div>
</div>
Expand Down
13 changes: 13 additions & 0 deletions src/simularium/SelectionInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface SelectionEntry {
export interface SelectionStateInfo {
highlightedAgents: SelectionEntry[];
hiddenAgents: SelectionEntry[];
colorChangeAgents: SelectionEntry[];
}

interface DisplayStateEntry {
Expand Down Expand Up @@ -218,6 +219,18 @@ class SelectionInterface {
return indices;
}

public getColorChangeAgentIds(info: SelectionEntry[]): number[] {
const requests = info;
let indices: number[] = [];

requests.forEach((r) => {
const name = r.name;
const tags = r.tags;
indices = [...indices, ...this.getIds(name, tags)];
});
return indices;
}

public clear(): void {
this.entries = new Map<string, DecodedTypeEntry>();
}
Expand Down
65 changes: 65 additions & 0 deletions src/test/SelectionInterface.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ describe("SelectionInterface module", () => {
{ name: "D", tags: [] },
],
hiddenAgents: [],
colorChangeAgents: [],
};
const ids = si.getHighlightedIds(selectionStateHighlight);
const allAs = [0, 1, 2, 3];
Expand All @@ -250,6 +251,7 @@ describe("SelectionInterface module", () => {
{ name: "D", tags: [""] },
],
hiddenAgents: [],
colorChangeAgents: [],
};
const ids = si.getHighlightedIds(selectionStateHighlight);

Expand All @@ -266,6 +268,7 @@ describe("SelectionInterface module", () => {
{ name: "E", tags: ["t1000"] },
],
hiddenAgents: [],
colorChangeAgents: [],
};
const ids = si.getHighlightedIds(selectionStateHighlight);

Expand All @@ -278,6 +281,7 @@ describe("SelectionInterface module", () => {
const selectionStateHighlight = {
highlightedAgents: [{ name: "E", tags: [""] }],
hiddenAgents: [],
colorChangeAgents: [],
};
const ids = si.getHighlightedIds(selectionStateHighlight);

Expand All @@ -295,6 +299,7 @@ describe("SelectionInterface module", () => {
{ name: "A", tags: [] },
{ name: "C", tags: [] },
],
colorChangeAgents: [],
};
const ids = si.getHiddenIds(selectionStateHide);

Expand All @@ -310,6 +315,7 @@ describe("SelectionInterface module", () => {
{ name: "A", tags: ["t1", "t2"] },
{ name: "B", tags: ["t1"] },
],
colorChangeAgents: [],
};
const ids = si.getHiddenIds(selectionStateHide);
expect(ids).toEqual([1, 2, 3, 5, 7]);
Expand All @@ -325,13 +331,70 @@ describe("SelectionInterface module", () => {
{ name: "A", tags: [""] },
{ name: "C", tags: ["", "t1", "t2"] },
],
colorChangeAgents: [],
};
const ids = si.getHiddenIds(selectionStateHide);

expect(ids).toEqual([0, 8, 9, 10, 11]);
});
});

describe("getColorChangeIds", () => {
test("Color change: select multiple by name", () => {
const si = new SelectionInterface();
si.parse(idMapping);
const selectionStateColor = {
highlightedAgents: [],
hiddenAgents: [],
colorChangeAgents: [
{ name: "A", tags: [] },
{ name: "C", tags: [] },
],
};
const ids = si.getColorChangeAgentIds(
selectionStateColor.colorChangeAgents
);

expect(ids).toEqual([0, 1, 2, 3, 8, 9, 10, 11]);
});

test("Color change: change color by name & tags", () => {
const si = new SelectionInterface();
si.parse(idMapping);
const selectionStateColor = {
highlightedAgents: [],
hiddenAgents: [],
colorChangeAgents: [
{ name: "A", tags: ["t1", "t2"] },
{ name: "B", tags: ["t1"] },
],
};
const ids = si.getColorChangeAgentIds(
selectionStateColor.colorChangeAgents
);
expect(ids).toEqual([1, 2, 3, 5, 7]);
});

test("Color change: change color by name & null tag", () => {
const si = new SelectionInterface();
si.parse(idMapping);

const selectionStateColor = {
highlightedAgents: [],
hiddenAgents: [],
colorChangeAgents: [
{ name: "A", tags: [""] },
{ name: "C", tags: ["", "t1", "t2"] },
],
};
const ids = si.getColorChangeAgentIds(
selectionStateColor.colorChangeAgents
);

expect(ids).toEqual([0, 8, 9, 10, 11]);
});
});

describe("getUIDisplayData", () => {
test("Doesn't crash", () => {
const si = new SelectionInterface();
Expand Down Expand Up @@ -406,6 +469,8 @@ describe("SelectionInterface module", () => {
});
});

describe("changeAgentColors", () => {});

describe("setAgentColors", () => {
const defaultColor = "#0";
const defaultColorListLength = 6;
Expand Down
Loading