Mpld3: 浏览器/HTML 指定图形大小而不是 figsize * dpi

创建于 2014-02-06  ·  31评论  ·  资料来源: mpld3/mpld3

真的很喜欢这个包,非常感谢分享。

这是一个建议的改进,但它并不完全符合 Python 风格。 但话又说回来,d3js 也不是 :)

图形的设置大小反映在屏幕上很好,但我认为有一个选项将画布大小设置为边界 div,然后让该 div 大小由浏览器宽度决定/无论如何否则开发商想要。

值得我在 _js.py 和 _object.py 中搞砸来实现这一点吗?

最有用的评论

@cliffckerr我绝对可以将它添加到draw_figure ,也许作为一个参数,它需要一个Object并在svg上设置该对象中指定的所有属性,所以你可以通过在{viewBox: ..., width: '90vw', height: 'auto'}之类的东西中。

我确实想问您和此线程中的其他人是否认为应该将其添加到其他任何地方,以支持例如fig_to_html() 。 如果是这样,也许我们应该想办法解决这个问题。 否则,请告诉我,我可以立即对draw_figure()进行更改。

所有31条评论

我不太确定你在问什么......我们从 matplotlib 图中获得了以英寸为单位的图尺寸,并从 matplotlib 图中获得了 dpi。 你建议我们如何改变这一点? 谢谢

而不是使用 Python 中设置的绝对图形大小,我的意思是这样的:

<div id='parent' class='figsizeinfo'>
//mpld3 generated code
</div>

其中 figsizeinfo 是 CSS 尺寸规范,而 mpld3 填充 div。 (根据我的经验,flotjs 是这样工作的)

嗯......这个问题可能会暴露我对网络内容的缺乏经验,但我认为 SVG(mpld3 使用)完全基于像素,并且不能轻易改变。 flotjs 是否使用 SVG 或其他规范?

SVG(可缩放矢量格式)图形是基于矢量的,而不是基于像素的。

这是一个使用 vanilla matplotlib 生成的 SVG 图像的示例,该图像随窗口大小缩放:

http://bleepshow.pithy.io/SVG_Example

(清楚地重复了你的例子)

据我了解,d3js 和所有画布绘图图形都是矢量,所以他们应该能够做到这一点。

我想,诀窍是设置

figwidth = $(“#parent”).width //(jquery based, but you get the point )

而不是

figwidth = figsize[0] * dpi;

是的,我知道 SVG 是基于矢量的,但除非我弄错了,否则画布的大小以及标记的大小及其在屏幕上的位置都是以磅为单位的。 编写 SVG 代码以针对具有任意窗口大小的任意图形正确缩放似乎非常复杂。

不,这很容易。

这是我应用于您的 fig_to_d3 代码的技巧:

print mpld3.fig_to_d3(fig).replace("\n","\r").replace("var figwidth = 8.0 * 80","var figwidth = $(window).width()*.9;").replace("var figheight = 6.0 * 80","var figheight = $(window).height()*.9;")

出现如下:

http://bleepshow.pithy.io/mpld3_window_scale_test

现在,标签在错误的位置,但再次“只是”将它们的位置参考到 div 而不是绝对参考数字。 但据我所知,该图的渲染效果很好。

(请注意,除非您刷新,否则这不会调整大小,但使用一点胶水也很简单)

我目前正在为自己设计一个基于此的解决方案,我很高兴尝试将其完善为适合拉取请求的东西。

mpld3 图形的响应大小将非常有用。 如果您使用按钮(在工具栏中)添加它,以便能够将当前图形打开到新窗口,并且整个图形将很容易调整大小。

+1

@hadim我想让它保持“pythonic”,所以像

mpld3.fig_to_d3(fig,size="adaptive")

将是一个很好的触发器

我同意 !

我知道制作不同尺寸的图形很容易。 但总的来说,我仍然不相信这是一个好主意。 一旦修改了图形大小,它将涉及修改所有线宽、标记位置、标记大小、字体大小等,这会给代码增加很多复杂性而没有太多好处。 此外,图例、轴标签和其他属性的正确放置取决于 plt.draw() 命令,该命令根据内部图形大小和 dpi 设置做出假设,老实说,我不知道如何轻松地重新设置-事后调整。

这个 mpld3 的理念是产生简单的输出,尽可能地反映 matplotlib 图中的内容。 如果要更改输出图形的大小,首选方法是调整 matplotlib 图形大小。 其他任何东西似乎都会很快成为实施、测试和维护的主要难题。

插件呢?

plugins.connect(fig, plugins.ResponsiveSize())

一个插件可能是一个很好的方法。 但同样,您如何处理调整字体大小、线宽、标记大小、图例位置和轴文本位置? 由于所有这些问题,如果没有一些广泛的基础设施来支持调整大小,我认为这样的插件的用处将非常有限。

@jakevdp我不同意:在我上面的 3 秒 hack 中唯一遭受的是标签位置,同样,这是编写更好的 javascript 的问题。 DOM 允许在没有太多工作的情况下进行绝对定位和相对位置。

现在实现代码的方式,一切都被硬编码到图中。 通过一些工作,宽度/高度、线条粗细和字体大小可以根据 div 大小进行线性缩放。 最棘手的部分是纵横比,并且可以锁定。 锁定纵横比后,线性缩放一切都非常简单

@hadim这是个好主意。

我不知道 d3.js 所以我不知道。 但是因为我们正在处理 svg 文件,我真的不认为我们不能轻易做到......

一些链接开始考虑最好的方法:

为@dansteingart +1。 为什么不将所有 SVG 内部长度和位置设置为相对坐标,然后在输出之前使用 viewBox 调整整个图形的大小,以便与 figsize matplotlib 参数匹配(或在其他情况下响应)。

@dansteingart - 我同意,只要有足够的 JS hack,你就可以让它工作。 但无论如何,我不支持从根本上修改此包以包含该功能。

为什么? 嗯,有一点是它违背了前面提到的包的理念,即绘图元素、图形大小等应该通过 matplotlib 接口定义。

其次,这不是一个“必须具备”的功能,从长远来看,使这种非必须具备的功能的代码库变得更加复杂会损害软件包。 有关为什么会这样的一些背景信息,请参阅@ellisonbg去年在 SciPy 的演讲

如果你想开发一个插件来添加这种行为,欢迎你。 如果它运行良好,甚至可能值得将其包含在plugins模块中。 但我坚决反对为了新功能而对基本图形布局进行重大修改,这与包装的理念背道而驰,无论它们多么酷。

我刚刚开始关注这一点,在我看来,某种插件可以完成某种有趣的响应式图形大小调整行为。 @dansteingart以一个功能的想法开始这个线程,以及一个关于是否值得以某种方式开始实现该功能的问题。 在回答这个问题时,我建议您从一个插件开始,看看在不更改 _objects.py 或 _js.py 的情况下能走多远。 但是,如果您愿意,我想退后一步,谈谈我们要解决的问题:

图形的设置大小反映在屏幕上很好,但我认为有一个选项将画布大小设置为边界 div,然后让该 div 大小由浏览器宽度决定/无论如何否则开发商想要。

我想澄清一下这将出现的用例。 在我的常规工作流程中,我将 ipython 与在云中运行的笔记本服务器一起使用,并最大化我的 Web 浏览器。 因此,如果我从工作显示器切换到笔记本电脑显示器并且屏幕宽度更小,我可能会遇到这种情况。 但我敢肯定还有其他人正在考虑的其他设置。 还有什么?

@jakevdp 很公平,我同意在 python 端不应该有任何改变。 但是,我认为这在 JS 方面都是公平的,如果实验的目的是结合 matplotlib 和 d3js 的最佳方面,我认为值得一试。

在我看来,一旦你调用了 fig_to_d3,你就离开了 python 的领域,并且使图形响应 = 编写更好的 JS。

至于响应式页面的实用性,仅对于 iPython 输出,我同意你的看法,但 python 不仅仅是 iPython 笔记本,我认为最终使用 mpl3d 创建大小响应式网页将比你在这里暗示的更有用。

根据您的逻辑,如果我想放大与 matplotlib 保持一致的细节,我应该只更改 xlim/ylim。

再次感谢伟大的软件包,我会看看我不能用插件做什么,然后回复你。

@aflaxman

我想澄清一下这将出现的用例。 在我的常规工作流程中,我将 ipython 与在云中运行的笔记本服务器一起使用,并最大化我的 Web 浏览器。 因此,如果我从工作显示器切换到笔记本电脑显示器并且屏幕宽度更小,我可能会遇到这种情况。 但我敢肯定还有其他人正在考虑的其他设置。 还有什么?

http://pithy.io

我写的精辟让我/我的小组/我的班级编写脚本,然后变成网络应用程序。 让身材适合窗户让生活更美好。 MPL3d 为我提供了一个更好的工具来制作交互式绘图(我正在到处乱搞),如果交互式绘图是大小响应的,那么一切都赢了。

谢谢@dansteingart。 请记住,即使 JS 对 Python 用户隐藏,它仍然是代码,仍然需要维护。 多年来,我在开源开发方面的经验是,经常出现对实现新功能感到兴奋的人,一旦这些功能被合并,它们的维护和维护就落在了少数投资于该软件包的开发人员的肩上长期。 我已经非常过度投入,以至于我不得不忽略几年前创建的常用软件包的错误报告。 我真的不希望 mpld3 达到这一点。

感谢您的理解,我期待看到您可以将什么放在一个插件中。

@jakevdp这一点很好,我认为插件架构可以很好地实现这一点。 如果它坏了,那将是我的错,而不是你的(也就是说,除非你改变 fig_to_d3 :-p )

重写已经登陆,这可能_稍微_更容易实现为插件,至少在特殊情况下是这样。 不过,我并没有考虑到这种动态情况来写它,所以可能会有一些陷阱。 如果您在这方面取得任何进展,请告诉我。

嗨,感谢伟大的项目。 在这个问题上是否有任何进展? 是否开发了插件/功能? 具体来说,我指的是“将画布大小设置为边界 div 的选项”。 谢谢。

我认为这是一个有价值的功能,但在绘制后供参考,您可以使用 d3 使图形自动缩放(此处为窗口高度)

fetch("d3/" + figure + ".json")
    .then((response) => response.json())
    .then((data) => mpld3.draw_figure(figure, data))
    .then(() => {
        d3.select("#" + figure)
            .selectAll(".mpld3-figure")
            .attr("width", "100%")
            .attr("height", "70vh")
            .attr("viewBox", "0 0 1200 800")
            .attr("preserveAspectRatio", "xMinYMin meet");
    });

在这里,我将第二次使用@hadim@carlinmack使用viewBox 。 其实可以很简单。 例如,如果您当前有<svg width="1200" height="800"> ,请尝试改用<svg viewBox="0 0 1200 800"> 。 而已。 viewBox定义了 svg 内部的坐标系, widthheight参数成为可选参数,并像任何其他元素一样定义外部尺寸。 您也可以使用width=100%或直接通过 css 设置值(css 的宽度和高度优先于属性)。

我在最近的 chrome 版本中成功使用了它。 应该调查跨浏览器依赖的细节,但我认为底线很清楚。

PS: https ://css-tricks.com/scale-svg 有一篇背景文章,但是当我上面概述的方法有效(至少在现代浏览器中)并且在概念上很简单时,我发现它令人困惑: viewBox = "0 0 ${width} ${height}"用于内部代码, width=...height=...作为 svg 属性或 css 参数用于重新缩放,如有必要。

是的,这正是@carlinmack 所建议的。 我对“使用 d3 使图形自动缩放”感到困惑,因为它是纯 HTML / CSS,但是好的,操作 DOM 是 d3 所做的。 @carlinmack指示的“preserveAspectRatio”是我相信的默认值(至少这是 css-tricks.com 链接中解释的内容)。 如果仍然保留纵横比,为什么要指示height="70vh" ? 对于非常狭窄和高大的人物来说,这是某种上限吗?

正确,我不希望肖像人物高于视口:)

除了它使图形比必要的大,当需要与周围内容紧密配合时不合适。 改用max-height对我有用。

这是我最终在浏览器中加载 mpld3 图形的方式:

      let figureID = "id_12345" ; 
      let dataURL = figureID + ".json" ; 

      d3.json(dataURL).then( function(data) {
        mpld3.draw_figure(figureID, data);
        return data;
      }).then( function(data) {
        d3.select("#" + figureID)
          .selectAll(".mpld3-figure")
          .attr("width", null)   // remove "width" and "height" attributes as set by mpld3
          .attr("height", null)  
          .attr("viewBox", `0 0 ${data.width} ${data.height}`)
      });

感谢@carlinmack @perrette的讨论! 巧合的是,我们也遇到了这个问题,@dkong-idm 的解决方案是:

    const resizeChart = (viewBoxSettings) => {
        let svg = document.getElementsByClassName("mpld3-figure");

        if (svg && svg.length > 0) {
            svg[0].setAttribute("viewBox",viewBoxSettings );
            svg[0].setAttribute("width", "90vw");
            svg[0].setAttribute("height", "auto");
        }
    }

@vladh ,将这个自动缩放功能添加到mpld3中是否需要做很多工作,或者作为draw_figure的可选参数,或者作为独立函数?

@cliffckerr我绝对可以将它添加到draw_figure ,也许作为一个参数,它需要一个Object并在svg上设置该对象中指定的所有属性,所以你可以通过在{viewBox: ..., width: '90vw', height: 'auto'}之类的东西中。

我确实想问您和此线程中的其他人是否认为应该将其添加到其他任何地方,以支持例如fig_to_html() 。 如果是这样,也许我们应该想办法解决这个问题。 否则,请告诉我,我可以立即对draw_figure()进行更改。

@vladh是的,它在fig_to_html()中也非常有用。

此页面是否有帮助?
0 / 5 - 0 等级