Table of Contents
- Introduction
- Running Plugins
- Setting up your development environment
- Recipies for plugin development: HOWTO…
- HOWTO add a menu action
- HOWTO add a toolbar action
- HOWTO add an action to the right-click menu
- HOWTO create a sidebar panel
- HOWTO add a new experimental data visualization style
- HOWTO add a new pathway importer / exporter
- HOWTO add custom shapes
- HOWTO save session preferences
- HOWTO add a panel to the preference dialog
- HOWTO add information to the backpage
- HOWTO add a a custom property to the properties tab
- Publishing your plugin
- Plugins in other programming languages
Introduction
It is impossible for one piece of bioinformatics software to suit every type of experimental data, every type of analysis or every type of visualization. That's why the plugin interface of PathVisio is very important: it let's you customize PathVisio to your needs.
What can a plugin do?
What type of things can be a plugin? Here is a list of ideas. You can create plugins to:
- Import or export to a new pathway file format
- Import experimental data from a webservice and display it on pathways
- Use a new style of data visualization, for example graphs instead of the simple colored boxes.
- Implement a new statistical method for comparing expression on pathway
- And many more...
Theoretically, every aspect of PathVisio can be customized. The menu's, the main window, the visualization engine and the expression data manager. There is no limit to what plugins can do.
In practice, there may be things that are not convenient to change, i.e. it would take a lot of work to get the type of customization you want. In those cases, please contact us to discuss what you want to achieve. You may have stumbled on a new type of usage that we haven't thought of, and we would love to hear from you. We may be able to modify the core of PathVisio to make your work easier.
Running Plugins
Note Webstart security model prevents plugins from local disk to be added to them. If you want to run a plugin, either run PathVisio from your IDE, or install PathVisio using one of the methods described in AlternativeInstallation
You can specify the location of your plugin with the -p command-line option. PathVisio expects one of three things after the -p option:
- A jar file, for example -p /home/martijn/helloworld.jar
- A directory containing multiple jar files, for example -p /home/martijn/cool/plugin/directory
- A fully specified class name of a class that implements org.pathvisio.Plugin, for example -p org.pathvisio.plugin.HelloWorld. For this to work the specified class has to be on the Class-Path. This is only interesting for developers because end-users have no control over the Class-Path. But for developing / testing it can be really useful.
Finally, there is a default plugin directory where you can place your plugin, in which case it will be automatically detected and loaded without having to specify the location.
Setting up your development environment
At this time, we highly recommend always using the latest subversion trunk of PathVisio. PathVisio is still in development, and relying on a release tarball may let your plugin get out of date quicker than you'd think.
To set up your build environment in Eclipse, see: PluginEclipseSetup?
Now create a separate Eclipse project and write your Plugin class there. Make sure you set the pathvisio project as a dependency of the plugin project, so that all exposed classes of PathVisio are available in your plugin and it compiles correctly. Specify the -p <your.PluginClass?> as a program argument in the run configuration.
To troubleshoot, do make sure that:
- Both pathvisio and your plugin compile without errors.
- Because your plugin project normally depends on the pathvisio project, all classes that are in pathvisio are also available in the plugin but not the other way around. Hence, the run configuration should use the plugin as project.
- specify the regular main class of PathVisio as the class to run: org.pathvisio.gui.swing.GuiMain?
A note on API stability
As mentioned, PathVisio is not completely stable. The API changes occasionally, and all plugins have to be updated. At the moment, we rely on automated continuous integration testing to make sure that all plugins conform to the API at all times. If an API leads to a broken plugin, we will notify and try to fix it automatically.
See this blog entry for an explanation of the PathVisio stable API policy
HOWTO package your plugin as a jar
For quicker plugin loading, specify the class using the PathVisio-Plugin-Class Manifest attribute.
For example, add these lines to your build.xml:
<target name="jar" depends="build">
<jar jarfile="${jar.name}">
<manifest>
<attribute name="PathVisio-Plugin-Class" value="org.pathvisio.plugins.HelloPlugin"/>
</manifest>
<fileset dir="build" includes="**/*.class"/>
</jar>
</target>
If the PluginManager? can't find the PathVisio-Plugin-Class attribute in the manifest, it will scan the jar file for classes that implement the Plugin interface. This can take more than a few seconds on a large jar file.
Plugin libraries
If your plugin needs libraries that are not included in PathVisio, you have to unjar them and package them in the plugin jar. You can use the <unjar> ant task. For example add this code before the <jar> task call:
<unjar dest="${class.dir}">
<fileset dir="${lib.dir}" includes="**/*.jar"/>
</unjar>
Recipies for plugin development: HOWTO…
HOWTO add a menu action
The easiest way is to register your action in your plugins' init method:
public void init(PvDesktop desktop) { // register our action in the "Help" menu. desktop.registerMenuAction ("Help", helloAction); }
Of course you need to define your action as well. A simple action looks like this:
/** * Display a welcome message when this action is triggered. */ private class HelloAction extends AbstractAction { HelloAction() { // The NAME property of an action is used as // the label of the menu item putValue (NAME, "Welcome message"); } /** * called when the user selects the menu item */ public void actionPerformed(ActionEvent arg0) { JOptionPane.showMessageDialog( desktop.getFrame(), "Hello World"); } }
See HelloWorldPlugin for the complete listing.
HOWTO add a toolbar action
You can add either an javax.swing.Action or a javax.swing.Component and add it to the Toolbar.
// add our action to the toolbar
desktop.getSwingEngine().getApplicationPanel().addToToolbar(toolbarAction);See the complete example: ExToolbar.java See also VisualizationPlugin?
HOWTO add an action to the right-click menu
You can hook into the context menu that appears when you right-click on a Pathway element
// register a hook so we can modify the right-click menu desktop.addPathwayElementMenuHook(new PathwayElementMenuHook() { /** * This method is called whenever the user right-clicks * on an element in the Pathway. * VPathwayElement contains the object that was clicked on. */ public void pathwayElementMenuHook(VPathwayElement e, JPopupMenu menu) { // We instantiate an Action ShowInfoAction showInfoAction = new ShowInfoAction(); // pass the clicked element to the action object showInfoAction.setElement(e); // Insert action into the menu. // NB: this is optional, we can choose e.g. // to insert only when the clicked element is a certain type. menu.add (showInfoAction); } }
Where ShowInfoAction? is defined as
private class ShowInfoAction extends AbstractAction { private VPathwayElement elt; public ShowInfoAction() { // This will be the label of the pop up menu item. putValue (NAME, "What class is this?"); } /** * This should be called before the action is triggered */ public void setElement (VPathwayElement anElt) { elt = anElt; } public void actionPerformed(ActionEvent arg0) { // Display a message with the actual class JOptionPane.showMessageDialog(desktop.getFrame(), "You clicked a " + elt.getClass(), "Class Information", JOptionPane.INFORMATION_MESSAGE); } }
See also the PPPiP plugin for a real-world example.
HOWTO create a sidebar panel
public void init(PvDesktop desktop) { this.desktop = desktop; // create a new panel to show in the side bar JPanel mySideBarPanel = new JPanel (); mySideBarPanel.setLayout (new BorderLayout()); mySideBarPanel.add (new JLabel ("Hello SideBar"), BorderLayout.CENTER); // get a reference to the sidebar JTabbedPane sidebarTabbedPane = desktop.getSideBarTabbedPane(); // add or panel with a given Title sidebarTabbedPane.add("Title", mySideBarPanel); }
(See ExSidepanel.java)
The chempaint plugin uses this technique to display structural formulas for metabolites in the side panel.
HOWTO add a new experimental data visualization style
You have to extend the VisualizationMethod? class. Then you can register new methods as follows:
//Register the visualization methods VisualizationMethodRegistry reg = desktop.getVisualizationMethodRegistry(); reg.registerMethod( ColorByExpression.class.toString(), new VisualizationMethodProvider() { public VisualizationMethod create(Visualization v, String registeredName) { return new ColorByExpression(v, registeredName, desktop.getGexManager()); } } );
See the VisualizationPlugin for an example.
HOWTO add a new pathway importer / exporter
You should start by creating a class that implements either the PathwayImport? or PathwayExport? interface, or both.
Then you register them like so in your init() method:
// instantiate TextLinesImporter, our own importer, and register it desktop.getSwingEngine().getEngine().addPathwayImporter(new TextLinesImporter()); // here we register an instance of our exporter desktop.getSwingEngine().getEngine().addPathwayExporter(new BibliographyExporter());
If the plug-in is loaded correctly, you can access the importer / exporter by clicking File->Import or File->Export. It will now show up in file type drop-down in the file chooser dialog.
See ExImporter.java and ExExporter.java
See also the HtmlExport? plugin for a real-world example: http://svn.bigcat.unimaas.nl/pvplugins/trunk/htmlexport
HOWTO add custom shapes
TODO
HOWTO save session preferences
The PreferenceManager? provides a way to save values from one session to the next. For example, to add a measure of user-friendliness, we can use the PreferenceManager? to save the current directory of a JFileChooser, so that the next time we open it, it will open in the last used directory. Of all possible directories, the last used directory is the most likely to contain the file the user is looking for.
In order to store a preference, we have to instantiate a class that implements the Preference interface. The Preference interface provides both a name (which will be used as key in the properties file) and a default value. If you want to define multiple Preferences for your plugin, the easiest way is to define a enum, although there are also other ways to do this. For example:
enum ExPreference implements Preference { EXAMPLE_LAST_OPENED_DIR (System.getProperty("user.home")); ExPreference (String defaultValue) { this.defaultValue = defaultValue; } private String defaultValue; public String getDefault() { return defaultValue; } }
To get and set a value, use one of the PreferenceManager?.getXxxx() or PreferenceManager?.setXxxx() methods. The preferences will be automatically loaded and saved by the PathVisio framework to a properties file (Usually ~/.PathVisio/.PathVisio)
Here is an example:
JFileChooser jfc = new JFileChooser(); // set current directory to what was stored in the preferences // default: home directory. jfc.setCurrentDirectory( PreferenceManager.getCurrent().getFile(ExPreference.EXAMPLE_LAST_OPENED_DIR)); int status = jfc.showOpenDialog(desktop.getFrame()); if(status == JFileChooser.APPROVE_OPTION) { // save current directory of jfc. // next time will be opened in same location. PreferenceManager.getCurrent().setFile(ExPreference.EXAMPLE_LAST_OPENED_DIR, jfc.getCurrentDirectory()); }
See ExPreferences.java See also the ZScore Plugin for a real-world example
HOWTO add a panel to the preference dialog
The previous HOWTO explains how to use the PreferenceManager? to save session state variables. Of course you can also use PreferenceManager? to save actual user preferences. Saving and retrieving user preferences is exactly the same, the only difference is that you should make them available in the Preferences Dialog that you can access in the edit menu.
All you have to do is use PreferencesDlg?.builder() to obtain a PreferencePanel?.Builder() object, to which you add the Preference's one by one. Finally call the build() method when it's done and add it to the dialog with dlg.addPanel(), Here is a simple example that defines a Color preference and an integer preference:
PreferencesDlg dlg = desktop.getPreferencesDlg();
dlg.addPanel("Example Plugin",
dlg.builder()
.colorField(ExPreference.EXAMPLE_COLOR, "Example Color")
.integerField(ExPreference.EXAMPLE_INT, "Example Integer between 0 and 100", 0, 100)
.build()
);HOWTO add information to the backpage
TODO
HOWTO add a a custom property to the properties tab
You can store custom information in the pathway using dynamic properties. A plugin can register a custom dynamic property to the properties tab, so users can edit this property for the selected pathway element. To do this, your plugin needs to implement the property interface for the property you want to add:
static final Property MY_GENERAL_PROPERTY = new Property () { //A unique id for the property public String getId() { return "org.pathvisio.example.MyProperty"; } //The description, wiill be used as tooltip in the property panel public String getDescription() { return "This is an example property"; } //The name the user sees in the property panel public String getName() { return "Example property"; } //The data type of the property public PropertyType getType() { return StaticPropertyType.STRING; } public boolean isCollection() { return false; } };
And then register the property to the PropertyManager and PropertyDisplayManager:
PropertyManager.registerProperty(MY_GENERAL_PROPERTY); PropertyDisplayManager.registerProperty(MY_GENERAL_PROPERTY);
This will make the property appear in the property panel for any pathway element. If you want the property to apply to a specific pathway element only, you can set the scope of the property after registering it. For example, to register a property that only applies to elements with type DataNode? and Label:
PropertyManager.registerProperty(MY_SPECIFIC_PROPERTY);
PropertyDisplayManager.registerProperty(MY_SPECIFIC_PROPERTY);
PropertyDisplayManager.setPropertyScope(
MY_SPECIFIC_PROPERTY,
EnumSet.of(ObjectType.DATANODE, ObjectType.LABEL)
);For a complete example of this plugin, please see ExDynamicPropertyPanel.java
Publishing your plugin
HOWTO unit test your plugin
- How to make a webstart out of your plugin: PluginWebstart
- How to send your plugin to us...
Plugins in other programming languages
Plugins are not restricted to Java: they can be written in any programming language that can run on the Java Virtual Machine (JVM). So this includes Jython, Groovy and JRuby.
