放大 Plotly 热图

2023-11-29

目前 Plotly.JS 热图中有 2 种“缩放”行为:

  1. 在这里,您可以采用任何矩形形状进行缩放(单击、拖放)。但是像素不是正方形的,这对于某些应用程序来说是不行的(不保留长宽比,有时应该保留):

        const z = Array.from({length: 500}, () => Array.from({length: 100}, () => Math.floor(Math.random() * 255)));
        Plotly.newPlot('plot', [{type: 'heatmap', z: z}], {});
        <script src="https://cdn.plot.ly/plotly-2.16.2.min.js"></script>
        <div id="plot"></div>
  2. 这里是像素是正方形的谢谢{'yaxis': {'scaleanchor': 'x'}}, 但是之后您只能缩放具有特定纵横比的矩形形状,这有时是 UX/UI 的限制因素:

        const z = Array.from({length: 500}, () => Array.from({length: 100}, () => Math.floor(Math.random() * 255)));
        Plotly.newPlot('plot', [{type: 'heatmap', z: z}], {'yaxis': {'scaleanchor': 'x'}});
        <script src="https://cdn.plot.ly/plotly-2.16.2.min.js"></script>
        <div id="plot"></div>

Question:如何同时拥有两者,即可以绘制任意形状的矩形选择缩放?并保留正方形像素?缩放的对象应位于绘图的中心(如果需要,可以使用水平或垂直空白)。


一种方法是首先设置scaleanchor与期望的约束scaleratio,这样一旦绘制了图形,我们就可以计算约束缩放范围比,从而产生所需的像素与单位比例,而无需太多麻烦。

然后,我们可以删除约束并附加一个情节重排事件处理程序将在必要时进行调整。由于这些调整是通过调用精确地进行的Plotly.relayout(),我们通过条件块并通过仅考虑合理数量的有效数字来比较范围比来防止无限循环。

如果重新布局后的比率与目标(受限)比率不匹配,我们将通过扩大其中一个轴范围(而不是缩小另一个轴范围)来调整它,同时保持用户创建的缩放窗口相对于调整范围居中。

const z = Array.from({length: 500}, () => Array.from({length: 100}, () => Math.floor(Math.random() * 255)));

const data = [{
  type: 'heatmap',
  z: z
}];

const layout = {
  xaxis: {
    constrain: 'range',
    constraintoward: 'center',
    scaleanchor: "y",
    scaleratio: 1
  }
};

Plotly.newPlot('plot', data, layout).then(afterPlot);

function afterPlot(gd) {
  // Reference each axis range
  const xrange = gd._fullLayout.xaxis.range;
  const yrange = gd._fullLayout.yaxis.range;

  // Needed when resetting scale
  const xrange_init = [...xrange];
  const yrange_init = [...yrange];

  // Compute the actual zoom range ratio that produces the desired pixel to unit scaleratio
  const zw0 = Math.abs(xrange[1] - xrange[0]);
  const zh0 = Math.abs(yrange[1] - yrange[0]);
  const r0 = Number((zw0 / zh0).toPrecision(6));

  // Now we can remove the scaleanchor constraint
  // Nb. the update object references gd._fullLayout.<x|y>axis.range
  const update = {
    'xaxis.range': xrange,
    'yaxis.range': yrange,
    'xaxis.scaleanchor': false,
    'yaxis.scaleanchor': false
  };

  Plotly.relayout(gd, update);

  // Attach the handler that will do the adjustments after relayout if needed
  gd.on('plotly_relayout', relayoutHandler);

  function relayoutHandler(e) {
    if (e.width || e.height) {
      // The layout aspect ratio probably changed, need to reapply the initial
      // scaleanchor constraint and reset variables
      return unbindAndReset(gd, relayoutHandler);
    }

    if (e['xaxis.autorange'] || e['yaxis.autorange']) {
      // Reset zoom range (dblclick or "autoscale" btn click)
      [xrange[0], xrange[1]] = xrange_init;
      [yrange[0], yrange[1]] = yrange_init;
      return Plotly.relayout(gd, update);
    }

    // Compute zoom range ratio after relayout
    const zw1 = Math.abs(xrange[1] - xrange[0]);
    const zh1 = Math.abs(yrange[1] - yrange[0]);
    const r1 = Number((zw1 / zh1).toPrecision(6));

    if (r1 === r0) {
      return; // nothing to do
    }

    // ratios don't match, expand one of the axis range as necessary

    const [xmin, xmax] = getExtremes(gd, 0, 'x');
    const [ymin, ymax] = getExtremes(gd, 0, 'y');

    if (r1 > r0) {
      const extra = (zh1 * r1/r0 - zh1) / 2;
      expandAxisRange(yrange, extra, ymin, ymax);
    }
    if (r1 < r0) {
      const extra = (zw1 * r0/r1 - zw1) / 2;
      expandAxisRange(xrange, extra, xmin, xmax);
    }

    Plotly.relayout(gd, update);
  }
}

function unbindAndReset(gd, handler) {
  gd.removeListener('plotly_relayout', handler);

  // Careful here if you want to reuse the original `layout` (eg. could be
  // that you set specific ranges initially) because it has been passed by
  // reference to newPlot() and been modified since then.
  const _layout = {
    xaxis: {scaleanchor: 'y', scaleratio: 1, autorange: true},
    yaxis: {autorange: true}
  };

  return Plotly.relayout(gd, _layout).then(afterPlot);
}

function getExtremes(gd, traceIndex, axisId) {
  const extremes = gd._fullData[traceIndex]._extremes[axisId];
  return [extremes.min[0].val, extremes.max[0].val];
}

function expandAxisRange(range, extra, min, max) {
  const reversed = range[0] > range[1];
  if (reversed) {
    [range[0], range[1]] = [range[1], range[0]];
  }
  
  let shift = 0;
  if (range[0] - extra < min) {
    const out = min - (range[0] - extra);
    const room = max - (range[1] + extra);
    shift = out <= room ? out : (out + room) / 2;
  }
  else if (range[1] + extra > max) {
    const out = range[1] + extra - max;
    const room = range[0] - extra - min;
    shift = out <= room ? -out : -(out + room) / 2;
  }

  range[0] = range[0] - extra + shift;
  range[1] = range[1] + extra + shift;

  if (reversed) {
    [range[0], range[1]] = [range[1], range[0]];
  }
}
<script src="https://cdn.plot.ly/plotly-2.22.0.min.js"></script>
<div id="plot"></div>

铌。在处理程序中,除了检查用户是否刚刚重置比例时之外,我们使用对gd._fullLayout.<x|y>axis.range而不是检查包含的内容e(传入的事件对象),因为引用始终是最新的,并且它们的结构永远不会改变,这与仅反映更新内容的事件参数不同。另外,因为update对象本身引用这些引用,它允许稍微不那么冗长,只需调用Plotly.relayout(gd, update)修改范围后。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

放大 Plotly 热图 的相关文章

  • Javascript 中的无限原型继承

    我正在学习 Javascript 中的原型继承 根据我的理解 我尝试使用它来将进程发送到无限递归链接中 我对原型继承的想法是一个对象 它是一个函数 保存原型链接 该对象的任何实例都指向它 因此 如果我说instance someproper
  • React:如何从 Material-UI TextField 组件获取值

    我有一个小型应用程序 其中包含 Form 组件 SubmitButton 组件和我的父组件 App js 当用户单击提交按钮时 我想获取表单组件上 3 个字段的值并将它们传递给我的 App js 组件 我不确定如何使用触发事件onClick
  • Node.js req.body 在表单数据内容类型中未定义

    在这里 我为这个表单数据传递 API 创建了一个小演示 现在我正在使用邮递员检查此 API 但我没有收到任何数据 Code const http require http const express require express cons
  • 输入类型货币格式,带逗号和小数位 2

    我只是想问如何制作输入类型文本的货币格式的JavaScript 当您输入数字时 数字是否可能带有逗号 另外 如何使数字固定为 2 个小数 如果我输入 3 位小数 最后一个数字将四舍五入 因此可以是 2 位小数 我有一个仅接受数字的文本框 我
  • 点击后 Dash DropDown 关闭

    我不希望下拉菜单在选择值后关闭 我希望它在我的页面上保持打开状态 我正在使用 dcc Dropdown dcc Dropdown id job type options self options placeholder Select one
  • jquery .load() 不起作用

    我似乎无法让 jquery 的 load 函数工作 一定是我缺少的一些简单的东西 基本上只是试图将 more html 的片段加载到 index html 中 索引 html
  • 提交后如何重置表单?

    我有一个简单的表格 假设它需要一个电子邮件地址 提交表单后 消息堆栈会通知用户其地址已成功提交 问题是 提交地址后 带有电子邮件的表单字段仍然包含用户输入的电子邮件地址 我该如何重置该字段 我必须为此使用 JavaScript 吗 谢谢 w
  • 绘图不显示

    我正在使用闪亮的 但无法显示绘图 之前就出现过 不知道怎么变了 MRE global r 或将其放入 server r 中 library shinydashboard library plotly server r shinyServer
  • Firestore onSnapshot() 方法多次触发

    我有一个带有多个路由和 vuex 的 vue cli 4 应用程序 Firestore 数据库已成功连接 我的应用程序立即反映从 Firestore 控制台应用于数据库的修改 在离开包含与 Firestore 同步 的组件的路线然后返回后
  • 在 Javascript 中按日期对数组进行排序

    我在用着sort 按日期排序数组 elements data sort function a b return a date getTime b date getTime 问题是某些元素缺少日期 或日期无效 这导致了这个错误 无法读取属性
  • 在 AMP 中包含自定义 JavaScript 的最佳方式

    我阅读了有关脚本标记的所有文档 但找不到如何在 AMP HTML 中包含自定义 JavaScript 我知道
  • 有没有办法防止 neDB 集合数组中的条目重复?

    var addNewUser function id chatId db update id id push users chatId function err numAffected code after the record is up
  • 我可以使用 javascript 生成 JSON 文件吗?

    我想在域 example1 com 上创建一个页面 并获取 解析另一个域 example2 com json json 上的 JSON 文件 可以使用 javascript 生成 json 文件 在 example2 com 上 吗 我认为
  • RegEx 使用 match() 在 JavaScript 中提取字符串数组

    我正在尝试使用string match 在 javascript 中使用正则表达式来提取字符串数组 这是一个示例字符串 CREATE TABLE listings listing id INTEGER UNIQUE state TEXT t
  • Javascript onclick隐藏div

    我想使用 javascript 隐藏这个警告 div 我的 javascript 正确吗 我想在单击关闭图标时隐藏 关闭 div images close icon gif div strong Warning strong These a
  • 如何获取元素相对于当前屏幕位置的偏移量?

    我正在尝试用纯 Javascript 重构所有 jQuery 除了非常具体的值之外 一切都正常工作 根据此代码的浏览器供应商 我得到了不同的值 对于 jQuery 我会使用 var topSelected figure offset top
  • Dojo require,模块加载失败时连接错误

    当我尝试加载不存在的模块时 它失败并出现 404 错误 当然 我想处理此错误 但不知道如何连接到 错误 事件 根据 Dojo 文档 我应该能够使用它的微事件 API http livedocs dojotoolkit org loader
  • JavaScript TypedArray 混合类型

    我正在尝试使用 WebGL 并希望将一些不同类型混合到一个字节缓冲区中 我知道 TypedArrays 可以达到这个目的 但不清楚我是否可以与它们混合类型 OpenGL 顶点数据通常是与无符号字节或整数混合的浮点数 在我的测试中 我想将 2
  • Bootstrap $('#myModal').modal('show') 不起作用

    我不知道为什么 但所有模态功能都不适用于我 我检查了版本和负载 它们都很好 我不断收到此错误消息 Uncaught TypeError modal is not a function 对于隐藏我已经找到了替代方案 代替 myModal mo
  • 根据对象内的值将对象数组分成两部分

    我一直在尝试 并努力 弄清楚如何根据键值对拆分对象数组 长话短说 我有一个火车正在停靠的车站列表 需要将之前的停靠点和未来的停靠点分开 我正在使用的数据如下所示 station code SOC station name Southend

随机推荐

  • 为什么 .length 不是一个需要 () 的方法

    JavaScript中为什么关键字长度不需要 似乎所有其他函数 例如 splice shift 都需要括号 我们只能推测为什么它被设为普通属性而不是方法 但是 那 length是每个字符串 数组的常量值 它在计算时不会修改任何内容 它不像方
  • 避免警告“非依赖属性的设置方法不应访问...”

    我有一个类 它有一些属性 并且有 2 个相关 在示例中称为param1 param2 他们是独立的 只是受到约束 param2必须一样大或大于param1并且必须始终存在 如果param1做 有问题的代码类似于 function set p
  • boost asio 缓冲区延迟分配

    异步操作 现在我传递预分配的字节缓冲区 例如 s async receive from boost asio buffer preallocated pointer preallocated size remote endpoint boo
  • 如何从一个 HTML5 画布拖放到另一个画布

    我试图弄清楚如何将图像从一个画布拖放到另一个画布 假设画布彼此相邻 是否可以无缝地将某些东西拖过边界 如果不是 将 div 拖到画布上 获取其 ID 然后通过响应画布上的 mouseup 位置来放置它是不是更好 您不能在画布上拖动项目 画布
  • 如何检查是否有任何 JavaScript 事件侦听器/处理程序附加到元素/文档? [复制]

    这个问题在这里已经有答案了 尝试在线搜索 但看起来我无法正确制定搜索查询 我如何使用 jQuery 或仅使用 javascript 列出附加到元素 文档 窗口或存在于 DOM 中的所有处理程序或事件侦听器 在 1 8 之前的 jQuery
  • 有理数 - ruby​​ 中的原始数字

    如何获得原始号码 例如当我输入 r Rational 2 10 1 5 2和10将更改为1和5 r numerator 1 r denominator 5 如何从 Rational 类的实例中获取 2 和 10 r 我对 Rational
  • Android:DCIM 文件夹中的重复照片存储

    我正在使用本机 Android 相机并将文件保存到应用程序数据文件夹 mnt sdcard Pictures 同时 在某些设备上 照片的另一个副本会保存到 DCIM 文件夹中 这是我的代码 private void startStockCa
  • Inno Setup 根据可执行调用的结果有条件重新启动

    我的 Inno Setup 脚本用于安装驱动程序 它运行我的InstallDriver exe在步骤中复制此文件后ssInstall 我需要根据返回的值要求用户在某些情况下重新启动InstallDriver exe 这意味着我不能把Inst
  • Pandas dataframe:从列中的字符串中提取浮点值

    我正在尝试从特定列的字符串中提取浮动值 原始输出 DATE strCondition 4 3 2018 2 9 4 3 2018 3 1 text 4 3 2018 2 6 text 4 3 2018 text 2 7 和其他变化 我也尝试
  • ASP.NET MVC 下的 SSL 页面

    如何对基于 ASP NET MVC 的站点中的某些页面使用 HTTPS Steve Sanderson 在预览版 4 上有一个关于如何以 DRY 方式执行此操作的非常好的教程 网址为 http blog codeville net 2008
  • Django,使用其他表中的数据进行注释和排序

    在我的应用程序中 有请求物品的用户和捐赠这些物品的用户 我想获取所有捐款最多的用户 这些是我的模型 class ItemRequest models Model item type models ForeignKey ItemType de
  • 当 html 表单允许文件上传时,Django 停止并显示“生成器引发 StopIteration”

    我的设置是 Windows 10 Python 3 7 Apache 2 4 mod wsgi 当我添加这个时enctype multipart form data 在我的表单中 仅通过添加此属性 仅 没有文件附加到表单 提交时出现此错误
  • nginx。被 CORS 政策阻止

    当前 nginx 配置 server listen hidden 80 server name dev hidden com root var www back hidden api location add header Access C
  • csv 读取引发“UnicodeDecodeError:'charmap'编解码器无法解码...”

    我已经阅读了我能找到的所有帖子 但我的情况似乎很独特 我对 Python 完全陌生 所以这可能是基础的 我收到以下错误 UnicodeDecodeError charmap 编解码器无法解码位置 70 中的字节 0x8d 字符映射到未定义
  • 如何将日期选择器包装在新的 div 中?

    我需要将我的日期选择器放在一个新的 div 中 这将是一个 shadow border div 我尝试过以下方法 beforeShow function input input datepicker widget find ui datep
  • 最大字符串数组 VisualBasic WSH

    我正在 VB 中编写一个 WSH 脚本 以读取通过 Run 方法使用重定向目录列表生成的大量目录列表 目录列表大约有 8400 行 但是每次我运行脚本时 都会出现以下循环 执行直到 DirList AtEndOfStream Redim 保
  • 我可以手动注册/安装 Search.Collat​​orDSO.1

    我目前正在尝试使用 windows search 服务搜索一些索引文件 我的问题是 Windows 搜索无法安装在网络服务器上 因为它是 网络版本 收到的错误消息是 Search Collat orDSO 1 提供程序未在本地计算机上注册
  • Windows 忽略 JAVA_HOME:如何将 JDK 设置为默认值?

    如何说服 Windows 使用 JDK 而不是 JRE 这个问题之前已经在这里和其他地方被问过 如何设置默认 Java 安装 运行时 Windows 问题是 Windows 忽略了JAVA HOME它还忽略了我将 JDK bin 目录作为路
  • 如何检测Android是否完全支持USB?

    我的应用程序使用UsbManager与 USB 摄像头通信 有些设备不支持 USB 这些将返回null for UsbManager context getSystemService Context USB SERVICE 或者他们会抛出一
  • 放大 Plotly 热图

    目前 Plotly JS 热图中有 2 种 缩放 行为 在这里 您可以采用任何矩形形状进行缩放 单击 拖放 但是像素不是正方形的 这对于某些应用程序来说是不行的 不保留长宽比 有时应该保留 const z Array from length