How to access MViewPane after creating + promoting new table

User 2d015c38e4

10-06-2009 02:06:50

I have a NetBeans plugin to IJC where I select a molecule in a table, run a query on the selected molecule (which consists of passing the molecule to some custom algorithmic code that returns a list of result molecules), and then I display these results in a new table.  I now want to be able to highlight or color some of the atoms in the result molecules that I have displayed in the new table.   Looking over the forums and code examples it looks like I need to be able to access a MViewPane object for the new table so that I can do something like the following:


MViewPane mpan ...;
mpan.setAtomSetColor(0, Color.black);
mpan.setAtomSetColor(1, Color.red);


Unfortunately I can't figure out where to find the MViewPane instance and am not that familiar with Swing...can anyone help me with this?  The following is an example of the code that I'm using to create the new table and populate it with Molecules.  Thanks.


 


 


final DFEntity entity ...  // DFEntity from currently selected node in original table


final Molecule mol ... // Selected molecule to use for query


 


DFSchema schema = entity.getSchema();
final DFNewType entityNewTypeForNewJChemBaseEntity = DIFUtilities.findFirstAppropriateNewType(
         schema.getEntities().getNewTypes(),
         false,
         new Class[] { JChemBaseEntityCapability.class },
         new Class[0]);
assert entityNewTypeForNewJChemBaseEntity != null;


if (!(opt instanceof DFNewTypeWellKnownOptions.NewJChemBaseEntity)) {
        System.out.println("Something is wrong, the options should be of this type!");
}


DFNewTypeOptions opt = entityNewTypeForNewJChemBaseEntity.getOptions();
DFNewTypeWellKnownOptions.NewJChemBaseEntity options = (DFNewTypeWellKnownOptions.NewJChemBaseEntity) opt;
String queryName = String.format("Query");
options.setNewDFItemNameSafe(queryName);

 // Table names can't have spaces in them and must be unique
options.setTableName(options.getNewDFItemName().replaceAll(" ", "")); // set your table name here



UIBackgroundRunnerRW runner = new UIBackgroundRunnerRW(schema.getLockable(), "Promoting jchem table to entity", false) {
     DFEntity newEntity;
     @Override
     public void phase1InRequestProcessor() {
          
                // It's expected that this new type creates only one entity.
                Collection newEntityCol = entityNewTypeForNewJChemBaseEntity.create(getEnvironment());
                newEntity = newEntityCol.iterator().next();
                // Utility to create a datatree for entity the simple way. DFNewTypes can be used as well.
                DFDataTree dataTree = DIFUtilities.createDataTreeForEntity(newEntity, getEnvironment());
                DIFUtilities.createViewForDataTree(dataTree, null, true, getEnvironment());


                ArrayList<Molecule> results = runQuery(mol);


      }


 


        @Override
        public void phase2InAWT() {


               updateEntityWithResults(newEntity, results);


        }


}


runner.start();


 


public static void updateEntityWithResults(DFEntity entity, ArrayList<Molecule> results) {
        DFEntityDataProvider edp = DIFUtilities.findEntityDataProvider(entity);
        
        String structureFieldId = "none";
        for (DFField f : entity.getFields().getItems()) {
            DFFieldStructureCapability structCapability = (DFFieldStructureCapability) DIFUtilities.findCapability(f, DFFieldStructureCapability.class);
            if (structCapability != null) {
                structureFieldId = f.getId();
                break;
            }
        }
       
        
        // create a lock for the edp...
        DFLock edpLock = DIFUtilities.getLockable(edp).obtainLock("updating field");
        DFEnvironmentRW edpEnv = EnvUtils.createDefaultEnvironmentRW(edpLock, "Populating query results", false);


        Map<String, Object> rowValues = new HashMap<String, Object>();


        Iterator<Molecule> results_itr = results.iterator();


        while (results_itr.hasNext()) {


              Molecule mol = results_itr.next();


              // Color MolAtoms here ....


              MarvinStructure structure = new MarvinStructure(mol);      
             rowValues.put(structureFieldId, structure);
             try {
                 edp.insert(rowValues, null, edpEnv);
             } catch (Exception e) {
                 System.out.println(String.format("Failed to add %s to query results.", structure));
                 e.printStackTrace();
             }
        }

        edpLock.release();
        edpEnv.getFeedback().finish();
    }


 

ChemAxon 909aee4527

10-06-2009 08:13:42

Dear Patrick,


the topic was moved to the Instant JChem forum, the relevant colleagues will answer soon.


Kind regards,
Judit

ChemAxon e189db4705

11-06-2009 02:54:50

Hello,

unfortunately getting the instance of MViewPane is not so simple, because:
- currently we don't have API for accessing and modifying renderers directly through DIF APIs (I mean through DFView's "configuration" property)
- the MViewPane instance exists only when form/gridview is opened
- even when form/gridview is opened, MViewPane is encapsulated (hidden inside) StructureRenderer.
- And StructureRenderer class is not part of API at the moment. Renderers are accessible only through IJCWidgets.
- And the last problem is that current implementation of StructureRender is calling setAtomSetColor depending on current search (highlighting of search structure). So again, even if you reach the MViewPane instance and set these colors, the renderer will change them again (based on http://www.chemaxon.com/jchem/doc/api/chemaxon/util/HitColoringAndAlignmentOptions.html)

The possible solution is to create your own renderer, but it would be pretty complex.
The other option is that we can make these color properties somehow available through APIs (we can do it in next version if we discuss what exactly is necessary). Then you will need to add these steps to the code:
1. Invoke gridview Opening when data are filled in entity
2. Wait till gridview is properly opened (it's possibe to register listener for this)
3. when view is opened get the current org.openide.nodes.Node[] and obtain IJCWidget from it
4. Test if it's instance of IJCWidget.RendererProvider (http://www.chemaxon.com/instantjchem/ijc_latest/docs/developer/api/com-im-ijc-core/com/im/ijc/core/api/views/IJCWidget.RendererProvider.html) and obtain the renderer instance.
5. For structure field the renderer can be cast (in most cases) to StructureRendererCapability. In 2.5.x release only a few methods are available here, but not those for changing colors. We would need to add them for next release. (http://www.chemaxon.com/instantjchem/ijc_latest/docs/developer/api/com-im-ijc-core/com/im/ijc/core/api/renderers/extra/StructureRendererCapability.html).


The modified code will look then like this ("setColors()" method is not in API, it's just for testing):





final DFEntity entity = fields.get(0).getEntity();



        DFSchema schema = entity.getSchema();

        final DFNewType entityNewTypeForNewJChemBaseEntity = DIFUtilities.findFirstAppropriateNewType(

                schema.getEntities().getNewTypes(),

                false,

                new Class[]{JChemBaseEntityCapability.class},

                new Class[0]);

        assert entityNewTypeForNewJChemBaseEntity != null;


        DFNewTypeOptions opt = entityNewTypeForNewJChemBaseEntity.getOptions();

        if (!(opt instanceof DFNewTypeWellKnownOptions.NewJChemBaseEntity)) {

            System.out.println("Something is wrong, the options should be of this type!");

        }


        DFNewTypeWellKnownOptions.NewJChemBaseEntity options = (DFNewTypeWellKnownOptions.NewJChemBaseEntity) opt;

        String queryName = String.format("Query");

        options.setNewDFItemNameSafe(queryName);


        // Table names can't have spaces in them and must be unique

//        options.setTableName(options.getNewDFItemName().replaceAll(" ", "")); // set your table name here


        UIBackgroundRunnerRW runner = new UIBackgroundRunnerRW(schema.getLockable(), "Creating a new jchem table to entity", false) {


            private DFEntity newEntity;

            private DFField structureField;

            private List<MarvinStructure> results;

            private DFView view;


            @Override

            public void phase1InRequestProcessor() {


                // It's expected that this new type creates only one entity.

                Collection<DFEntity> newEntityCol = entityNewTypeForNewJChemBaseEntity.create(getEnvironment());

                newEntity = newEntityCol.iterator().next();

                // Utility to create a datatree for entity the simple way. DFNewTypes can be used as well.

                DFDataTree dataTree = DIFUtilities.createDataTreeForEntity(newEntity, getEnvironment());

                view = DIFUtilities.createViewForDataTree(dataTree, null, true, getEnvironment());


                results = new ArrayList<MarvinStructure>();


                results.add(new MarvinStructure("CC1=CC(=O)C=CC1=O"));

                results.add(new MarvinStructure("S(SC1=NC2=CC=CC=C2S1)C3=NC4=C(S3)C=CC=C4"));

                structureField = updateEntityWithResults(newEntity, results);

            }


            @Override

            public void phase2InAWT() {

                TopComponent.getRegistry().addPropertyChangeListener(new PropertyChangeListener() {

                    public void propertyChange(PropertyChangeEvent evt) {

                        if (TopComponent.Registry.PROP_ACTIVATED.equals(evt.getPropertyName())) {

                            TopComponent.getRegistry().removePropertyChangeListener(this);

                            IJCWidgetCookie cake = findIJCWidgetCookieIfAvailable(TopComponent.getRegistry().getActivatedNodes());

                            if (cake != null) {

                                findStructureRendererAndChangeColors(structureField, cake);

                            }

                        }

                    }

                });

                AbstractViewTopComponent.getViewRegistry().open(view);

            }

        };


        runner.start();

    }


    protected static IJCWidgetCookie findIJCWidgetCookieIfAvailable(Node[] activatedNodes) {

        if (activatedNodes.length == 1) {

            IJCWidgetCookie ijcwc = activatedNodes[0].getCookie(IJCWidgetCookie.class);

            if (ijcwc != null) {

                return ijcwc;

            }

        }

        return null;

    }


    static void findStructureRendererAndChangeColors(DFField structureField, IJCWidgetCookie ijcWidgetCookie) {

        IJCWidget widget = ijcWidgetCookie.getWidget();

        if (widget instanceof IJCWidget.RendererProvider) {

            IJCWidget.RendererProvider widgetProvidingRenderer = (IJCWidget.RendererProvider) widget;

            Object r = widgetProvidingRenderer.getRendererForField(structureField);

            if (r instanceof StructureRendererCapability) {

                ((StructureRendererCapability) r).setColors();

            }

        }

    }


    static DFField updateEntityWithResults(DFEntity entity, List<MarvinStructure> results) {

        DFEntityDataProvider edp = DIFUtilities.findEntityDataProvider(entity);


        DFField structureField = null;

        for (DFField f : entity.getFields().getItems()) {

            DFFieldStructureCapability structCapability = (DFFieldStructureCapability) DIFUtilities.findCapability(f, DFFieldStructureCapability.class);

            if (structCapability != null) {

                structureField = f;

                break;

            }

        }

        String structureFieldId = structureField.getId();


        // create a lock for the edp...

        DFLock edpLock = DIFUtilities.getLockable(edp).obtainLock("updating field");

        DFEnvironmentRW edpEnv = EnvUtils.createDefaultEnvironmentRW(edpLock, "Populating query results", false);


        Map<String, Object> rowValues = new HashMap<String, Object>();


        Iterator<MarvinStructure> results_itr = results.iterator();


        while (results_itr.hasNext()) {


            // Color MolAtoms here ....


            MarvinStructure structure = results_itr.next();

            rowValues.put(structureFieldId, structure);

            try {

                edp.insert(rowValues, null, edpEnv);

            } catch (Exception e) {

                System.out.println(String.format("Failed to add %s to query results.", structure));

                e.printStackTrace();

            }

        }


        edpLock.release();

        edpEnv.getFeedback().finish();

        return structureField;

    }


Petr

User 2d015c38e4

12-06-2009 08:27:49

Thanks so much for getting back to me!


I have a few more questions/comments about your two possible suggested solutions.


 


Creating a custom renderer:


How hard is it to create a custom renderer?  I looked at the example for creating a renderer at http://www.chemaxon.com/instantjchem/ijc_latest/docs/developer/api/examples/addrenderer/index.html and wasn't sure how much of that applied to creating a structural renderer.  Is there an example somewhere for creating a structural renderer?  Could the StructureRenderer class be opened up in the API and then perhaps extended to create a custom structural renderer?


 


Adding color changing API methods to the StructureRendererCapability class:


All I would really need here are the color settings methods for the atom and bond sets like the ones in MarvinPane.  What is the likelihood and timeframe for such an addition?


 


You also mentioned that "the last problem is that current implementation of StructureRender is calling setAtomSetColor depending on current search (highlighting of search structure). So again, even if you reach the MViewPane instance and set these colors, the renderer will change them again  (based onhttp://www.chemaxon.com/jchem/doc/api/chemaxon/util/HitColoringAndAlignmentOptions.html)."  I'm not sure this is really the case/concern for me as I'm not running an IJC substructure query for my workflow and so there shouldn't be a current search.  Let me be a little bit more specific about my use case: 


1. I grab all the molecules in an IJC table and convert them into my own graph format (within my graph format I embed mappings between a Molecule's MolAtoms and MolBonds to the nodes and edges of my graph representation for the molecule)


2. I pass this set of molecules represented as graphs to a closed frequent subgraph mining algorithm which returns all closed subgraphs of my input set of graphs that meet a required support level in my input graph set.  With these subgraph results I also return the set of graphs for which each subgraph is supported in, as well as mappings between the nodes and edges of a subgraph and it's supporting graphs.


3. Now that I have my frequent subgraphs with supporting graphs, I want to display the supporting set of graphs for each subgraph in an IJC table as molecules with the subgraph part of the molecule highlighted a different color (I know exactly which MolAtoms and MolBonds are part of the subgraph for a Molecule due to the mappings I embedded in the graphs).  Throughout this process I never invoke the IJC substructure query mechanism and am fine if the user does this later on the results table causing my substructure coloring to disappear.


 


Any hints or tips on how I can go about implementing my proposed usage case is greatly appreciated.  Thanks.


-Patrick

ChemAxon fa971619eb

12-06-2009 13:05:19

Obviously there are a lot of possibilities and complexities here, but it might actually be very simple to achieve something here. If you are saving the molecules into the database already with the atoms and bonds assigned to the particular groups (you must save in mrv format for this to happen) then all you might need to do is to set the Colour scheme property of the renderer to 'group' to see the different colours.


This will take a bit of work to test, but its worth a try,


If you wish to set this property programatically (as opposed to manually in the UI) then this is not currently possible, but it should be fairly simple to add.


If this doesn't achieve what you need then the solution is likely to be a lot more complex, so lets investigate this approach first.


TIm


 

User 2d015c38e4

12-06-2009 19:09:36

OK, I tried setting the renderer color scheme to Group but now everything is just colored black the same way that the mono color scheme is.  I'm not entirely familar with the mrv format but does that just mean that Molecules have MDocuments associated with them?  Right now I'm loading MarvinStructures into the table which are created from Molecule's that I have combined with MDocuments.  The following is my code:


 


Molecule mol; // A molecule to display


MDocument mdoc = new MDocument(mol);


mdoc.setAtomSetColorMode(0, MDocument.SETCOLOR_SPECIFIED);
mdoc.setAtomSetRGB(0, Color.black.getRGB());
mdoc.setAtomSetColorMode(1, MDocument.SETCOLOR_SPECIFIED);
mdoc.setAtomSetRGB(1, Color.orange.getRGB());


// Set some atoms to color


int index; // Index of atom to color


MolAtom a = mol.getAtom(index);   
a.setSetSeq(1);


MarvinStructure structure = new MarvinStructure(mol); // Structure to add to table


 


Is there something I'm doing wrong/missing here?  Thanks.


 

ChemAxon fa971619eb

13-06-2009 18:16:00

OK, I have managed to test this now and there is a small bug that does stop the colouring being applied. This was simple to fix. You can try it by downloading the attached file named com-im-ijc-renderers.jar and replacing the current one which you will find in:
<path_to_ijc_install_dir>/instantjchem/modules.
Keep a backup of the old one just in case things go wrong!


With this you should be able to set the colour scheme to 'group' in the structure renderer settings and it should work.


If you want a simple test then load the attached file called hits.mrv.zip (after unzipping it) into IJC as a new structure table. The file contains structures in mrv format where certain parts of the structure (anilines) are hightlighed using the atom and bond sets.


Let us know how it goes!


Tim

User 2d015c38e4

16-06-2009 23:31:12

OK, so I tried out the new .jar file and I'm finally seeing atom coloring in gridview when I change the color scheme to Group!


 


Here are some remaining issues I have:


- I need to be able to programtically change the color scheme for the structure renderer to Group


-
When I change the color scheme of the structure renderer through the
GUI, the gridview doesn't refresh, and I need to close and reopen the
gridview in order to see the color change


- It doesn't look like
I have color control over the different groups.  Despite what I specify
in the setAtomSetRGB() method of MDocument, group 0 is always colored
black and group 1 is always colored red.  I've also noticed that group
2 is green, group 3 is blue, group 4 is cyan, etc.

ChemAxon fa971619eb

18-06-2009 16:29:00

Thanks. We will investigate those points.


Tim

ChemAxon e189db4705

02-07-2009 12:53:49

just a quick status update:












patmac wrote:


I need to be able to programtically change the color scheme for the structure renderer to Group

This will be now possible in upcoming release IJC 2.5.2 (should be released tomorrow or on Monday). We have added two new methods to StructureRendererCapability interface:


public void setColorScheme(String scheme);
public String getColorScheme();


It will be updated in documentation when release 2.5.2 is out.


When I change the color scheme of the structure renderer through the
GUI, the gridview doesn't refresh, and I need to close and reopen the
gridview in order to see the color change


This was a bug and it is also fixed now in 2.5.2.


It doesn't look like
I have color control over the different groups.  Despite what I specify
in the setAtomSetRGB() method of MDocument, group 0 is always colored
black and group 1 is always colored red.  I've also noticed that group
2 is green, group 3 is blue, group 4 is cyan, etc.


We are still investigating this. Will let you know later.


 


 


 

User 2d015c38e4

22-07-2009 00:47:52

I've updated to IJC 2.5.2 and see that when I change the color scheme of the structure field through the GUI the change is immediately displayed.  I'm not able to use the new getColorScheme() and setColorScheme() API calls added to StructureRendererCapability though.  When I try to use them I get a compile error saying that the methods don't exist.  I am able to compile with other methods from StructureRendererCapability such as isShowRGroups() however.  Can you confirm for me that these new API calls for StructureRendererCapability were added in the new release?  Thanks.


-Patrick

ChemAxon e189db4705

22-07-2009 09:53:02

I installed version 2.5.0 and updated it to 2.5.2 using auto-update feature. And I can confirm that my updated version contains these methods. If older methods are compilable and these new are not, I think it's problem of configuration only.


Could you please verify the version of com-im-ijc-core.jar module (display name is "Instant JChem Core")? You can find it under your IJC installation in instantjchem/modules/com-im-ijc-core.jar.


The version is written inside jar in META-INF/MANIFEST.MF. It should have version written there:


OpenIDE-Module-Specification-Version: 2.5.2


These items were added to interface in 2.5.2:


    public static final String[] COLOR_SCHEME_TAGS = {
        DispOptConsts.MONO_SCHEME_S,
        DispOptConsts.CPK_SCHEME_S,
        DispOptConsts.SHAPELY_SCHEME_S,
        DispOptConsts.GROUP_SCHEME_S
    };

    /** Sets the color scheme for the renderer.
     *
     * @param scheme One of the {@link #COLOR_SCHEME_TAGS} values
     */
    public void setColorScheme(String scheme);

    public String getColorScheme();  


Also javadoc was updated together with 2.5.2.


Let us know if this helps or not. thank you.


Petr