3

I'm making some mpld3 plots with linked information. I would like the points (which currently show tooltips) be clickable. Right now, I can embed HTML links into the tooltips, but they're not clickable since the tooltips disappear if you try to hover over them. Is this possible?

Here's an example page showing what I have done and approximately what I have in mind: http://www.eso.org/~aginsbur/EAACTF/EAACTF_plots_long.html

EDIT: My solution, based on the accepted answer, is:

class ClickInfo(mpld3.plugins.PluginBase):
    """mpld3 Plugin for getting info on click
    Comes from:
        http://stackoverflow.com/a/28838652/814354
    """

    JAVASCRIPT = """
    mpld3.register_plugin("clickinfo", ClickInfo);
    ClickInfo.prototype = Object.create(mpld3.Plugin.prototype);
    ClickInfo.prototype.constructor = ClickInfo;
    ClickInfo.prototype.requiredProps = ["id", "urls"];
    function ClickInfo(fig, props){
        mpld3.Plugin.call(this, fig, props);
    };

    ClickInfo.prototype.draw = function(){
        var obj = mpld3.get_element(this.props.id);
        urls = this.props.urls;
        obj.elements().on("mousedown",
                          function(d, i){
                            window.open(urls[i], '_blank')});
    }
    """
    def __init__(self, points, urls):
        self.points = points
        self.urls = urls
        if isinstance(points, matplotlib.lines.Line2D):
            suffix = "pts"
        else:
            suffix = None
        self.dict_ = {"type": "clickinfo",
                      "id": mpld3.utils.get_id(points, suffix),
                      "urls": urls}

which then gets used like this:

                    tooltip = mpld3.plugins.PointHTMLTooltip(points, labels,
                                                             voffset=10,
                                                             hoffset=10)
                    mpld3.plugins.connect(fig, tooltip)
                    mpld3.plugins.connect(fig, ClickInfo(points, urls))
keflavich
  • 18,278
  • 20
  • 86
  • 118

1 Answers1

6

I think you can create a new plugin to do this. Here is an example plugin that pops up an alert when a point is clicked.

You can modify it to open a new page by changing the alert(...); to window.open(url, '_blank')});:

   class ClickInfo(mpld3.plugins.PluginBase):
    """mpld3 Plugin for getting info on click        """

    JAVASCRIPT = """
    mpld3.register_plugin("clickinfo", ClickInfo);
    ClickInfo.prototype = Object.create(mpld3.Plugin.prototype);
    ClickInfo.prototype.constructor = ClickInfo;
    ClickInfo.prototype.requiredProps = ["id", "urls"];
    function ClickInfo(fig, props){
        mpld3.Plugin.call(this, fig, props);
    };

    ClickInfo.prototype.draw = function(){
        var obj = mpld3.get_element(this.props.id);
        urls = this.props.urls;
        obj.elements().on("mousedown",
                          function(d, i){ 
                            window.open(urls[i], '_blank')});
    }
    """
    def __init__(self, points, urls):
        self.points = points
        self.urls = urls
        if isinstance(points, matplotlib.lines.Line2D):
            suffix = "pts"
        else:
            suffix = None
        self.dict_ = {"type": "clickinfo",
                      "id": mpld3.utils.get_id(points, suffix),
                      "urls": urls}


fig, ax = plt.subplots()
points = ax.scatter(np.random.rand(50), np.random.rand(50),
                    s=500, alpha=0.3)
urls = ["http://example.com/#%d"%i for i in range(50)]

plugins.connect(fig, ClickInfo(points, urls))
mpld3.display()
keflavich
  • 18,278
  • 20
  • 86
  • 118
Abraham D Flaxman
  • 2,969
  • 21
  • 39
  • I needed to make a few modifications so that it more closely resembled https://mpld3.github.io/_modules/mpld3/plugins.html#PointHTMLTooltip, i.e. for matplotlib points & suffix stuff, but otherwise it worked great. Thanks! – keflavich Mar 03 '15 at 20:11
  • @keflavich would you link to your final solution? I'm working on something similar and running into issues with getting `window.open()` to work correctly – DathosPachy Aug 11 '15 at 00:08
  • @keflavich thanks, this seems to work! It looks like the error was trying to use `plt.plot(...)` instead of `plt.scatter(...)`. Also, if there's anyone else reading this, take note that following the style of many of the examples, the second-last line would be `plugins.connect(fig, ClickInfo(points[0], urls))` (note the bracket-zero after `points`.) The brackets seem to be necessary for using `plot`, but not `scatter`. – DathosPachy Aug 11 '15 at 13:37