From c1645c6c33cbc5f97fc32bc382ddbe43ea746ac0 Mon Sep 17 00:00:00 2001 From: Tibor Postek Date: Mon, 23 Mar 2020 16:34:50 +0100 Subject: [PATCH 1/2] #209 fix orientation of ngl view for all molecules from given site --- js/components/nglView/renderingObjects.js | 44 +++++++++++++------ .../preview/molecule/redux/dispatchActions.js | 24 +++++++--- js/reducers/ngl/actions.js | 4 +- js/reducers/ngl/nglReducers.js | 4 +- package.json | 2 +- 5 files changed, 54 insertions(+), 24 deletions(-) diff --git a/js/components/nglView/renderingObjects.js b/js/components/nglView/renderingObjects.js index 99b21622c..a7ebd25db 100644 --- a/js/components/nglView/renderingObjects.js +++ b/js/components/nglView/renderingObjects.js @@ -7,7 +7,7 @@ import { } from './generatingObjects'; import { concatStructures, Selection, Shape } from 'ngl'; -const showSphere = (stage, input_dict, object_name, representations) => { +const showSphere = (stage, input_dict, object_name, representations, orientationMatrix) => { let colour = input_dict.colour; let radius = input_dict.radius; let coords = input_dict.coords; @@ -20,7 +20,7 @@ const showSphere = (stage, input_dict, object_name, representations) => { return Promise.resolve(assignRepresentationArrayToComp(reprArray, comp)); }; -const showMol = (stage, input_dict, object_name, representations) => { +const showMol = (stage, input_dict, object_name, representations, orientationMatrix) => { let stringBlob = new Blob([input_dict.sdf_info], { type: 'text/plain' }); return stage.loadFile(stringBlob, { name: object_name, ext: 'sdf' }).then(comp => { const reprArray = @@ -33,13 +33,16 @@ const showMol = (stage, input_dict, object_name, representations) => { }) ]); - comp.autoView('ligand'); - + if (orientationMatrix) { + stage.viewerControls.orient(orientationMatrix); + } else { + comp.autoView('ligand'); + } return assignRepresentationArrayToComp(reprArray, comp); }); }; -const renderComplex = (ol, representations) => { +const renderComplex = (ol, representations, orientationMatrix) => { let cs = concatStructures( ol[4], ol[0].structure.getView(new Selection('not ligand')), @@ -67,14 +70,18 @@ const renderComplex = (ol, representations) => { }); const reprArray = representations || createRepresentationsArray([repr2, repr3]); - - comp.autoView('ligand'); + if (orientationMatrix) { + stage.viewerControls.orient(orientationMatrix); + } else { + comp.autoView('ligand'); + } + //TODO setFocus should be in condition comp.stage.setFocus(focus_let_temp); return assignRepresentationArrayToComp(reprArray, comp); }; -const showComplex = (stage, input_dict, object_name, representations) => { +const showComplex = (stage, input_dict, object_name, representations, orientationMatrix) => { let stringBlob = new Blob([input_dict.sdf_info], { type: 'text/plain' }); return Promise.all([ stage.loadFile(input_dict.prot_url, { ext: 'pdb' }), @@ -83,11 +90,11 @@ const showComplex = (stage, input_dict, object_name, representations) => { defaultFocus, object_name, input_dict.colour - ]).then(ol => renderComplex(ol, representations)); + ]).then(ol => renderComplex(ol, representations, orientationMatrix)); }; // ligand -const showEvent = (stage, input_dict, object_name, representations) => +const showEvent = (stage, input_dict, object_name, representations, orientationMatrix) => Promise.all( [ stage.loadFile(input_dict.pdb_info, { name: object_name, ext: 'pdb' }).then(comp => { @@ -114,7 +121,12 @@ const showEvent = (stage, input_dict, object_name, representations) => const repr4 = createRepresentationStructure(MOL_REPRESENTATION.ballPlusStick, { sele: 'LIG' }); - comp.autoView('LIG'); + + if (orientationMatrix) { + stage.viewerControls.orient(orientationMatrix); + } else { + comp.autoView('LIG'); + } const reprArray = representations || createRepresentationsArray([repr1, repr2, repr3, repr4]); return assignRepresentationArrayToComp(reprArray, comp); @@ -194,16 +206,20 @@ const showArrow = (stage, input_dict, object_name, representations, orientationM return Promise.resolve(assignRepresentationArrayToComp(reprArray, comp)); }; -const showProtein = (stage, input_dict, object_name, representations) => +const showProtein = (stage, input_dict, object_name, representations, orientationMatrix) => stage.loadFile(input_dict.prot_url, { name: object_name, ext: 'pdb' }).then(comp => { const reprArray = representations || createRepresentationsArray([createRepresentationStructure(input_dict.nglProtStyle, {})]); - comp.autoView(); + if (orientationMatrix) { + stage.viewerControls.orient(orientationMatrix); + } else { + comp.autoView(); + } return Promise.resolve(assignRepresentationArrayToComp(reprArray, comp)); }); -const showHotspot = (stage, input_dict, object_name, representations) => { +const showHotspot = (stage, input_dict, object_name, representations, orientationMatrix) => { if (input_dict.map_type === 'AP') { return stage.loadFile(input_dict.hotUrl, { name: object_name, ext: 'dx' }).then(comp => { const reprArray = diff --git a/js/components/preview/molecule/redux/dispatchActions.js b/js/components/preview/molecule/redux/dispatchActions.js index c616c7738..e2db9d523 100644 --- a/js/components/preview/molecule/redux/dispatchActions.js +++ b/js/components/preview/molecule/redux/dispatchActions.js @@ -79,7 +79,7 @@ const getViewUrl = (get_view, data) => { const handleVector = (json, stage, data) => (dispatch, getState) => { const state = getState(); const to_select = state.selectionReducers.to_select; - const orientationMatrix = state.nglReducers.moleculeOrientations[data.id]; + const orientationMatrix = state.nglReducers.moleculeOrientations[data.site]; var objList = generateObjectList(json['3d'], data); dispatch(setVectorList(objList)); // loading vector objects @@ -129,11 +129,15 @@ export const removeVector = (stage, data) => (dispatch, getState) => { dispatch(removeFromVectorOnList(generateMoleculeId(data))); }; -export const addComplex = (stage, data, colourToggle) => dispatch => { +export const addComplex = (stage, data, colourToggle) => (dispatch, getState) => { + const state = getState(); + const orientationMatrix = state.nglReducers.moleculeOrientations[data.site]; dispatch( loadObject( Object.assign({ display_div: VIEWS.MAJOR_VIEW }, generateComplexObject(data, colourToggle, base_url)), - stage + stage, + undefined, + orientationMatrix ) ).finally(() => { const currentOrientation = stage.viewerControls.getOrientation(); @@ -152,13 +156,21 @@ export const removeComplex = (stage, data, colourToggle) => dispatch => { dispatch(removeFromComplexList(generateMoleculeId(data))); }; -export const addLigand = (stage, data, colourToggle) => dispatch => { +export const addLigand = (stage, data, colourToggle) => (dispatch, getState) => { + const state = getState(); + const orientationMatrix = state.nglReducers.moleculeOrientations[data.site]; dispatch( - loadObject(Object.assign({ display_div: VIEWS.MAJOR_VIEW }, generateMoleculeObject(data, colourToggle)), stage) + loadObject( + Object.assign({ display_div: VIEWS.MAJOR_VIEW }, generateMoleculeObject(data, colourToggle)), + stage, + undefined, + orientationMatrix + ) ).finally(() => { const currentOrientation = stage.viewerControls.getOrientation(); dispatch(setOrientation(VIEWS.MAJOR_VIEW, currentOrientation)); - dispatch(setMoleculeOrientation(data.id, currentOrientation)); + + dispatch(setMoleculeOrientation(data.site, currentOrientation)); }); dispatch(appendFragmentDisplayList(generateMoleculeId(data))); }; diff --git a/js/reducers/ngl/actions.js b/js/reducers/ngl/actions.js index 5021c0c52..fe46686da 100644 --- a/js/reducers/ngl/actions.js +++ b/js/reducers/ngl/actions.js @@ -75,7 +75,7 @@ export const decrementCountOfPendingNglObjects = () => ({ type: CONSTANTS.DECREMENT_COUNT_OF_PENDING_NGL_OBJECTS }); -export const setMoleculeOrientation = (moleculeId, orientation) => ({ +export const setMoleculeOrientation = (moleculeGroupID, orientation) => ({ type: CONSTANTS.SET_MOLECULE_ORIENTATION, - payload: { moleculeId, orientation } + payload: { moleculeGroupID, orientation } }); diff --git a/js/reducers/ngl/nglReducers.js b/js/reducers/ngl/nglReducers.js index b8e49106b..1633c64f2 100644 --- a/js/reducers/ngl/nglReducers.js +++ b/js/reducers/ngl/nglReducers.js @@ -198,8 +198,10 @@ export default function nglReducers(state = INITIAL_STATE, action = {}) { case CONSTANTS.SET_MOLECULE_ORIENTATION: const newMoleculeOrientations = state.moleculeOrientations; - newMoleculeOrientations[action.payload.moleculeId] = action.payload.orientation; + if (newMoleculeOrientations[action.payload.moleculeGroupID] === undefined) { + newMoleculeOrientations[action.payload.moleculeGroupID] = action.payload.orientation; + } return Object.assign({}, state, { moleculeOrientations: newMoleculeOrientations }); default: diff --git a/package.json b/package.json index 4e52a20fb..2b30230ca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fragalysis-frontend", - "version": "0.3.1", + "version": "0.4.0", "description": "Frontend for fragalysis", "main": "webpack.config.js", "scripts": { From 53ca07993516d9d041d1e0b4a94d01c640c9858c Mon Sep 17 00:00:00 2001 From: Matej Vavrek Date: Tue, 24 Mar 2020 20:23:39 +0100 Subject: [PATCH 2/2] #183 added site id and compound id into filter dialog for further sorting options #208 hid compounds status labels --- .../preview/molecule/moleculeList.js | 4 +- .../molecule/moleculeListSortFilterDialog.js | 9 ++-- .../molecule/moleculeListSortFilterItem.js | 53 ++++++++++--------- .../preview/molecule/moleculeView.js | 4 +- .../preview/molecule/redux/constants.js | 42 +++++++++++---- 5 files changed, 68 insertions(+), 44 deletions(-) diff --git a/js/components/preview/molecule/moleculeList.js b/js/components/preview/molecule/moleculeList.js index 388ba33c1..f95fbb032 100644 --- a/js/components/preview/molecule/moleculeList.js +++ b/js/components/preview/molecule/moleculeList.js @@ -160,7 +160,6 @@ const MoleculeList = memo( const imgHeight = 34; const imgWidth = 150; - const [filteredCount, setFilteredCount] = useState(0); const [predefinedFilter, setPredefinedFilter] = useState(filter !== undefined ? filter.predefined : DEFAULT_FILTER); const isActiveFilter = !!(filterSettings || {}).active; @@ -180,6 +179,7 @@ const MoleculeList = memo( if (isActiveFilter) { joinedMoleculeLists = filterMolecules(joinedMoleculeLists, filterSettings); } else { + // default sort is by site joinedMoleculeLists.sort((a, b) => a.site - b.site); } @@ -333,7 +333,7 @@ const MoleculeList = memo( - Filters #{filteredCount} + Filters diff --git a/js/components/preview/molecule/moleculeListSortFilterDialog.js b/js/components/preview/molecule/moleculeListSortFilterDialog.js index 5c4d80449..949212b02 100644 --- a/js/components/preview/molecule/moleculeListSortFilterDialog.js +++ b/js/components/preview/molecule/moleculeListSortFilterDialog.js @@ -88,6 +88,7 @@ export const filterMolecules = (molecules, filterSettings) => { for (let molecule of molecules) { let add = true; // By default molecule passes filter for (let attr of MOL_ATTRIBUTES) { + if (!attr.filter) continue; const lowAttr = attr.key.toLowerCase(); const attrValue = molecule[lowAttr]; if ( @@ -105,15 +106,10 @@ export const filterMolecules = (molecules, filterSettings) => { // 2. Sort let sortedAttributes = filterSettings.priorityOrder.map(attr => attr); - sortedAttributes.push('site'); // Finally sort by site; return filteredMolecules.sort((a, b) => { for (let prioAttr of sortedAttributes) { - let order = 1; - if (prioAttr !== 'site') { - // Site is always arbitrary - order = filterSettings.filter[prioAttr].order; - } + const order = filterSettings.filter[prioAttr].order; const attrLo = prioAttr.toLowerCase(); let diff = order * (a[attrLo] - b[attrLo]); @@ -294,6 +290,7 @@ export const MoleculeListSortFilterDialog = memo( disabled={predefinedFilter !== 'none'} onChange={handleItemChange(attr)} onChangePrio={handlePrioChange(attr)} + filter={attrDef.filter} /> ); })} diff --git a/js/components/preview/molecule/moleculeListSortFilterItem.js b/js/components/preview/molecule/moleculeListSortFilterItem.js index 9ac40769b..27ae838ac 100644 --- a/js/components/preview/molecule/moleculeListSortFilterItem.js +++ b/js/components/preview/molecule/moleculeListSortFilterItem.js @@ -73,7 +73,7 @@ const widthMin = 30; const widthSlider = 170; const moleculeListSortFilterItem = memo(props => { - const { property, min, max, onChange, isFloat, color, disabled, onChangePrio } = props; + const { property, min, max, onChange, isFloat, color, disabled, onChangePrio, filter } = props; const { order, minValue, maxValue } = props; // Because Slider works only with Integers we convert Float to Int by multiplying with 100 const MULT = 100; @@ -165,28 +165,32 @@ const moleculeListSortFilterItem = memo(props => { - - {min} - - - { - return isFloat ? value / MULT : value; - }} - disabled={disabled} - /> - - - {max} - + {filter && ( + <> + + {min} + + + { + return isFloat ? value / MULT : value; + }} + disabled={disabled} + /> + + + {max} + + + )} ); }); @@ -198,7 +202,8 @@ moleculeListSortFilterItem.propTypes = { max: PropTypes.number.isRequired, color: PropTypes.string.isRequired, isFloat: PropTypes.bool, - disabled: PropTypes.bool + disabled: PropTypes.bool, + filter: PropTypes.bool }; export default moleculeListSortFilterItem; diff --git a/js/components/preview/molecule/moleculeView.js b/js/components/preview/molecule/moleculeView.js index 161630dea..5c51272bf 100644 --- a/js/components/preview/molecule/moleculeView.js +++ b/js/components/preview/molecule/moleculeView.js @@ -361,7 +361,7 @@ const MoleculeView = memo(({ imageHeight, imageWidth, data }) => { {target_on_name && data.protein_code && data.protein_code.replace(`${target_on_name}-`, '')} - {/* Status code */} + {/* Status code - #208 Remove the status labels (for now - until they are in the back-end/loader properly) {Object.values(molStatusTypes).map(type => ( @@ -370,7 +370,7 @@ const MoleculeView = memo(({ imageHeight, imageWidth, data }) => { ))} - + */} {/* Control Buttons A, L, C, V */} diff --git a/js/components/preview/molecule/redux/constants.js b/js/components/preview/molecule/redux/constants.js index 515839ba2..83c456331 100644 --- a/js/components/preview/molecule/redux/constants.js +++ b/js/components/preview/molecule/redux/constants.js @@ -7,55 +7,77 @@ export const constants = { }; export const MOL_ATTR = { + SID: { + key: 'site', + name: 'Site ID (SID)', + isFloat: false, + color: '#72e5be', + filter: false + }, + HID: { + key: 'id', + name: 'Hit ID (HID)', + isFloat: false, + color: '#daa520', + filter: false + }, MW: { key: 'MW', name: 'Molecular weight (MW)', isFloat: true, - color: '#f96587' + color: '#f96587', + filter: true }, - LOGP: { key: 'logP', name: 'logP', isFloat: true, color: '#3cb44b' }, + LOGP: { key: 'logP', name: 'logP', isFloat: true, color: '#3cb44b', filter: true }, TPSA: { key: 'TPSA', name: 'Topological polar surface area (TPSA)', isFloat: true, - color: '#ffe119' + color: '#ffe119', + filter: true }, - HA: { key: 'HA', name: 'Heavy atom count', isFloat: false, color: '#079ddf' }, + HA: { key: 'HA', name: 'Heavy atom count', isFloat: false, color: '#079ddf', filter: true }, HACC: { key: 'Hacc', name: '# H-bond acceptors (Hacc)', isFloat: false, - color: '#f58231' + color: '#f58231', + filter: true }, HDON: { key: 'Hdon', name: '# H-bond donors (Hdon)', isFloat: false, - color: '#86844a' + color: '#86844a', + filter: true }, ROTS: { key: 'Rots', name: '# Rotatable bonds (Rots)', isFloat: false, - color: '#42d4f4' + color: '#42d4f4', + filter: true }, RINGS: { key: 'Rings', name: '# rings (rings)', isFloat: false, - color: '#f032e6' + color: '#f032e6', + filter: true }, VELEC: { key: 'Velec', name: '# valence electrons (velec)', isFloat: false, - color: '#bfef45' + color: '#bfef45', + filter: true }, NCPD: { key: '#cpd', name: '# available follow-up cmpds. (#cpd)', isFloat: false, - color: '#fabebe' + color: '#fabebe', + filter: true } };