如何在mpld3中使用LinkedBrush插件“导出”所选点?(注:该问题涉及IT技术)

4
我正在尝试实现一个插件,它允许用户转储 LinkedBrush 插件选择的点的相关信息。我认为我的问题有点类似于这个例子。每个点都通过HTMLTooltip插件绑定了元信息,理想情况下,我也希望能够一并转储这些信息。在我提供的示例中,信息是通过提示框输出的。我希望能将此信息保存到某种文本文件中。

换句话说:我如何确定散点图中被LinkedBrush工具选中的点,以便我可以保存信息呢?


你能否包含一下你已经尝试过的内容?你卡在哪里了? - Abraham D Flaxman
请看下面我的回答。我非常乐意听取任何反馈,以使我的解决方案更加优雅。 - mattcart
可以在JS代码中执行Python命令-我会研究一下。最棒的技巧是当这些Python变量发生变化时,自动更新其他可视化内容。 - mdurant
1个回答

1
为了解决这个问题,我最终编辑了LinkedBrush插件代码。我添加了一个按钮,当点击时,使用brush.extent()输出刷子窗口的范围。这将打印出最小和最大的x和y坐标。我将基本上使用这些坐标来追溯输入数据集,并确定哪些点落在刷子的范围内。如果有更好的解决方法,欢迎提出。
class LinkedBrush(plugins.PluginBase):
JAVASCRIPT="""
  mpld3.LinkedBrushPlugin = mpld3_LinkedBrushPlugin;
  mpld3.register_plugin("linkedbrush", mpld3_LinkedBrushPlugin);
  mpld3_LinkedBrushPlugin.prototype = Object.create(mpld3.Plugin.prototype);
  mpld3_LinkedBrushPlugin.prototype.constructor = mpld3_LinkedBrushPlugin;
  mpld3_LinkedBrushPlugin.prototype.requiredProps = [ "id" ];
  mpld3_LinkedBrushPlugin.prototype.defaultProps = {
    button: true,
    enabled: null
  };
  function mpld3_LinkedBrushPlugin(fig, props) {
    mpld3.Plugin.call(this, fig, props);
    if (this.props.enabled === null) {
      this.props.enabled = !this.props.button;
    }
    var enabled = this.props.enabled;
    if (this.props.button) {
      var BrushButton = mpld3.ButtonFactory({
        buttonID: "linkedbrush",
        sticky: true,
        actions: [ "drag" ],
        onActivate: this.activate.bind(this),
        onDeactivate: this.deactivate.bind(this),
        onDraw: function() {
          this.setState(enabled);
        },
        icon: function() {
          return mpld3.icons["brush"];
        }
      });
      this.fig.buttons.push(BrushButton);
      var my_icon = "data:image/png;base64,longstring_that_I_redacted";
      var SaveButton = mpld3.ButtonFactory({
            buttonID: "save",
            sticky: false,
            onActivate: this.get_selected.bind(this),
            icon: function(){return my_icon;},
        });
      this.fig.buttons.push(SaveButton);
    }
    this.extentClass = "linkedbrush";
  }
  mpld3_LinkedBrushPlugin.prototype.activate = function() {
    if (this.enable) this.enable();
  };
  mpld3_LinkedBrushPlugin.prototype.deactivate = function() {
    if (this.disable) this.disable();
  };
  mpld3_LinkedBrushPlugin.prototype.get_selected = function() {
    if (this.get_selected) this.get_selected();
  };
  mpld3_LinkedBrushPlugin.prototype.draw = function() {
    var obj = mpld3.get_element(this.props.id);
    if (obj === null) {
      throw "LinkedBrush: no object with id='" + this.props.id + "' was found";
    }
    var fig = this.fig;
    if (!("offsets" in obj.props)) {
      throw "Plot object with id='" + this.props.id + "' is not a scatter plot";
    }
    var dataKey = "offsets" in obj.props ? "offsets" : "data";
    mpld3.insert_css("#" + fig.figid + " rect.extent." + this.extentClass, {
      fill: "#000",
      "fill-opacity": .125,
      stroke: "#fff"
    });
    mpld3.insert_css("#" + fig.figid + " path.mpld3-hidden", {
      stroke: "#ccc !important",
      fill: "#ccc !important"
    });
    var dataClass = "mpld3data-" + obj.props[dataKey];
    var brush = fig.getBrush();
    var dataByAx = [];
    fig.axes.forEach(function(ax) {
      var axData = [];
      ax.elements.forEach(function(el) {
        if (el.props[dataKey] === obj.props[dataKey]) {
          el.group.classed(dataClass, true);
          axData.push(el);
        }
      });
      dataByAx.push(axData);
    });
    var allData = [];
    var dataToBrush = fig.canvas.selectAll("." + dataClass);
    var currentAxes;
    function brushstart(d) {
      if (currentAxes != this) {
        d3.select(currentAxes).call(brush.clear());
        currentAxes = this;
        brush.x(d.xdom).y(d.ydom);
      }
    }
    function brushmove(d) {
      var data = dataByAx[d.axnum];
      if (data.length > 0) {
        var ix = data[0].props.xindex;
        var iy = data[0].props.yindex;
        var e = brush.extent();
        if (brush.empty()) {
          dataToBrush.selectAll("path").classed("mpld3-hidden", false);
        } else {
          dataToBrush.selectAll("path").classed("mpld3-hidden", function(p) {
            return e[0][0] > p[ix] || e[1][0] < p[ix] || e[0][1] > p[iy] || e[1][1] < p[iy];
          });
        }
      }
    }
    function brushend(d) {
      if (brush.empty()) {
        dataToBrush.selectAll("path").classed("mpld3-hidden", false);
      }
    }
    this.get_selected = function(d) {
        var brush = fig.getBrush();
        var extent = brush.extent();
        alert(extent);
    }
    this.enable = function() {
      this.fig.showBrush(this.extentClass);
      brush.on("brushstart", brushstart).on("brush", brushmove).on("brushend", brushend);
      this.enabled = true;
    };
    this.disable = function() {
      d3.select(currentAxes).call(brush.clear());
      this.fig.hideBrush(this.extentClass);
      this.enabled = false;
    };
    this.disable();
  };
    """
    def __init__(self, points, button=True, enabled=True):
        if isinstance(points, mpl.lines.Line2D):
            suffix = "pts"
        else:
            suffix = None
        self.dict_ = {"type": "linkedbrush",
                      "button": button,
                      "enabled": False,
                      "id": utils.get_id(points, suffix)}

太棒了!对我有用,有没有可能以任何方式将坐标获取到Python中? - applecider

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接