D3 反转色标图以获得幅度

2024-01-23

我有一个 colorscaleMap 让我们假设这样的事情

d3.scale.linear()
 .domain([0.01,0.02,0.03,0.04,0.05])
 .range(["#5100ff", "#00f1ff", "#00ff30", "#fcff00", "#ff0000"])

现在我想使用反转功能

假设 invert("#5100ff") ,我期望输出为 0.01,但反转功能不适用于非数字值。如中所述https://github.com/d3/d3-scale https://github.com/d3/d3-scale仅当范围是数字时才支持此方法。如果范围不是数字,则返回 NaN

问题:- 这与具有超过 10000 个数据点的大数据频谱图有关。 Y - 轴是频率,X 轴是时间,颜色代表幅度。我认为编写 Index 函数效率很低

有人有解决这个问题的办法吗?


这不是一件容易的任务,如果可能的话,最好通过使用绑定数据来避免该问题。

但是,这是一个非常有趣的问题。当反转数字时,您至少绑定到单个维度,数字将落入可插值的范围内(有一些特定的例外)。对于三维颜色空间,这变得有点困难,特别是对于分段域和范围。但即使我们抛开为比例尺无法产生的反转函数提供颜色,事情仍然很困难。

如前所述,d3-scale 不支持非数值反转,d3-interpolate 也不提供反转支持。我们也不可能有连续尺度的非数值域(这将提供最简单的解决方案)。在不重写每个颜色插值器的情况下,任何解决方案都可能特定于某个插值(默认值是每个通道上的线性插值,所以我将在下面使用它).

如果我们能够解决上述问题,最后一个挑战是您不能拥有太多的精度:RGB 通道值四舍五入为 0 到 255 之间的 8 位数字。反转该数字将产生舍入误差。

许多色标在任何给定通道上都不使用 0 - 255 的完整范围,这一事实通常会加剧这种舍入问题。如果从红色到橙色,变化最大的通道是绿色,变化为165。这肯定会降低任何反函数的精度。

也就是说,我们可以为具有颜色空间范围的比例创建简单的反转函数。这可能需要几个步骤:

  1. 查找范围的最小值和最大值之间最大范围的颜色通道(最小值和最大值为:a,b).
  2. 从需要反转的颜色中提取相同的颜色通道:y.
  3. 反插值y之间a and b,给我们t
  4. Take t并在尺度域的最小值和最大值之间进行插值

线性插值器如下所示:y = a + t * (b - a)

这样我们就可以用以下方法进行反插值:t = (y - a)/(b - a)

t是 0 到 1 之间的数字,其中(当应用于插值器时)0 将产生域中的最小值,1 将产生域中的最大值。

看起来可能是这样的:

var scale = d3.scaleLinear()
  .domain([0,100])
  .range(["orange","red"])


 scale.invertColor = function(x) {
    // get the color into a common form
    var color = d3.color(x); 
    
    // do the same for the range:
    var min = d3.color(this.range()[0]);
    var max = d3.color(this.range()[1]);
	
    // find out which channel offerrs the greatest spread between min and max:
    var spreads = [max.r-min.r,max.g-min.g,max.b-min.g].map(function(d) { return Math.abs(d); });
    var i = spreads.indexOf(Math.max(...spreads));
    var channel = d3.keys(color)[i];
	
    // The deinterpolation function	
    var deinterpolate = function (value,a,b) {
      if(b-a==0) return 0;  
      return Math.abs((value - a) / (b - a))
    }

	// Get t
	var t = deinterpolate(color[channel],min[channel],max[channel]);

    // Interpolate between domain values with t to get the inverted value:
    return d3.interpolate(...this.domain())(t)

};
  

  
var test = [0,10,50,90,100];
console.log("Test values:");
console.log(test)
console.log("Scaling and then Inverting values:");
console.log(test.map(function(d) { return scale.invertColor(scale(d)); }));
console.log("Original values minus scaled and inverted values:");
console.log(test.map(function(d) { return (d - scale.invertColor(scale(d))); }));
<script src="https://d3js.org/d3.v5.min.js"></script>

上面有限制,你可以喂任何颜色。即使该比例无法产生该值,它也会为您插入一个值。

通过多次使用上述函数,可以很容易地对多个段进行修改。我们可以检查每个段,看看每个段的值一旦反转后是否会缩放回自身。通过这样做,只能反转比例产生的颜色:

var scale = d3.scaleLinear()
  .domain([0,100,200])
  .range(["orange","red","purple"])


scale.invertColor = function(x) {
  var domain = this.domain();
  var range = this.range();
		
  // check each segment to see if the inverted value scales back to the original value:
  for(var i = 0; i < domain.length - 1; i++) {
    var d = [domain[i], domain[i+1]];
    var r = [range[i], range[i+1]];
		  
    var inverted = (invert(x,d,r))
    if (d3.color(this(inverted)).toString() == d3.color(x).toString()) return inverted;		
  }
  return NaN;  // if nothing matched
		
		
  function invert(x,d,r) {
    // get the color into a common form
    var color = d3.color(x); 
        
    // do the same for the range:
    var min = d3.color(r[0]);
    var max = d3.color(r[1]);
    	
    // find out which channel offerrs the greatest spread between min and max:
    var spreads = [max.r-min.r,max.g-min.g,max.b-min.g].map(function(d) { return Math.abs(d); });
    var i = spreads.indexOf(Math.max(...spreads));
    var channel = d3.keys(color)[i];
    	
    // The deinterpolation function	
    var deinterpolate = function (value,a,b) {
      if(b-a==0) return 0;  
      return Math.abs((value - a) / (b - a))
    }

    // Get t
    var t = deinterpolate(color[channel],min[channel],max[channel]);

    // Interpolate between domain values with t to get the inverted value:
    return d3.interpolate(...d)(t)	
  }
		
};
      

      
    var test = [0,10,50,90,100,110,150,190,200];
    console.log("Test values:");
    console.log(test)
    console.log("Scaling and then Inverting values:");
    console.log(test.map(function(d) { return scale.invertColor(scale(d)); }));
    console.log("Original values minus scaled and inverted values:");
    console.log(test.map(function(d) { return (d - scale.invertColor(scale(d))); }));
<script src="https://d3js.org/d3.v5.min.js"></script>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

D3 反转色标图以获得幅度 的相关文章

  • Typescript:按值检查对象是否存在于数组中

    我有这个数据 roles roleId 69801 role ADMIN roleId 69806 role SUPER ADMIN roleId 69805 role RB roleId 69804 role PILOTE roleId
  • 如何向 jQuery Tokeninput 添加占位符?

    如何将占位符添加到 jQuery Tokeninput 字段 一个正常的placeholder属性在这里不起作用 对于这样的输入
  • 计算Javascript中两次点击之间的时间

    我想用 javascript 计算属性的两次点击之间的时间 但我不知道如何 例如 a href click here a 如果用户单击多次 假设 5 秒内 我想显示警报 如果有帮助的话我正在使用 jQuery 我对 javascript 不
  • 在浏览器中语音聊天? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我们正在寻求建立一个小组 voice 使用服务器上的node js 在浏览器中聊天 这可能吗 如果您希望您的解决方案是基于服务器端和客
  • 将 jquery-mobile 与 Webpack 结合使用

    我正在尝试使用 webpack 加载 jquery mobile 但到目前为止还没有运气 我知道 jquery mobile 依赖于 jquery ui 而 jquery ui 又依赖于 jquery 如何在 Webpack 中设置这样的场
  • 禁用 JavaScript 中的右键单击

    当我尝试禁用右键单击时 它不起作用 我尝试使用下面的代码 document onclick function e console log e button if e button 2 e preventDefault return fals
  • 使用模态表单 ajax 超出 HTMLFormElement.toString 的最大调用堆栈大小

    我想使用模态窗口中的 ajax 请求提交表单 单击此链接可打开该模式 a class btn btn primary i class fa fa edit i Write a review a 模态窗口 div class modal fa
  • 如何使用 jQuery 向表中添加新行,并为其分配递增的 id

    我有一个现有的 HTML 表格 它是用户输入 GPS 点的表单的一部分 用户还可以选择上传 GPS 数据点 我想要一个用户可以按下的按钮 其中一些 Javascript 会向表中添加一个或多个新行 但新行必须继续增加表中使用的名称和 id
  • 使react-leaflet能够离线使用

    我一直在使用反应传单 https github com PaulLeCam react leaflet图书馆 到目前为止运作良好 现在我希望网站预加载尽可能多的图块 以便网络应用程序 也是 PWA 可以在没有互联网的情况下使用 我找到了一些
  • KeyboardEvent.keyCode 已弃用。这在实践中意味着什么?

    根据 MDN 我们绝对应该not正在使用 keyCode财产 它已被弃用 https developer mozilla org en US docs Web API KeyboardEvent keyCode https develope
  • jQuery 选择器:为什么 $("#id").find("p") 比 $("#id p") 更快

    该页面的作者 http 24ways org 2011 your jquery now with less suck http 24ways org 2011 your jquery now with less suck断言 jQuery
  • 如何从顺序键盘导航中删除 Vuetify 附加图标

    在带有 Vuetify 的 Vue js 应用程序中 我有一组用v text field并且其中有一个append icon为了切换文本可见性 如下所示
  • 如何在网页上实现文件上传进度条?

    当用户将文件上传到我的网络应用程序时 我想显示比动画 gif 更有意义的内容 我还有哪些可能性 编辑 我正在使用 Net 但我不介意是否有人向我展示与平台无关的版本 如果您对这一切在客户端通常如何工作感兴趣 就是这样 所有解决方案都通过 J
  • 如何在 e2e AngularJS 测试中进行文件上传?

    在我的一种观点中 我有一个文件上传控件 它支持通过拖放或单击按钮后打开的标准文件对话框上传文件 How to do this in my e2e tests1 1 Just one of the two options will be en
  • 有关于 PHP 中的 V8JS 的文档吗?

    有没有关于V8JS的文档 我是否只需要标准 PHP 或一些扩展即可使用 V8JS 我将非常感谢有关 PHP 中的 V8JS 的任何信息 要求 PHP 5 3 3 和 V8 库和标头安装在正确的路径中 Install http www php
  • Jquery,清除/清空 tbody 元素的所有内容?

    我认为这会相当简单 但似乎空方法无法清除我拥有的 tbody 如果有人知道执行此操作的正确方法 我将不胜感激 我只想删除 tbody 中包含的所有内容 到目前为止我正在尝试 tbodyid empty HTML table tbody tr
  • 从多维无穷大数组中删除数组元素

    我想删除一个特定元素 例如 我想删除元素id 76在下面的数组中 而且 数组可以无限地组合在一起 这里的问题是我无法刷新页面 因为我使用 Vue js 进行即时操作 如果我能做到这一点 我的下一个问题可能是如何在我现在想要的地方添加一个元素
  • 如何获取使用 .map 渲染的第一个元素的 ref?

    我需要在几行中显示视频 卡片 的缩略图 并重点关注第一个缩略图 我使用嵌套地图进行了显示 该代码基本上迭代视频数组并返回多行视频 我们如何关注第一个渲染的元素 我认为我们需要获得第一个要聚焦的元素的引用 但是我们如何在这里设置 ref 并在
  • 您如何看待引导模式触发器的相应回调?

    On 引导模态 http getbootstrap com javascript modals 我们知道我们可以为触发器绑定事件 例如show or hide using show shown hide hidden 但此事件绑定仅适用于一
  • React Native - 跨屏幕传递数据

    我遇到了一些麻烦react native应用程序 我不知道如何跨屏幕传递数据 我意识到还有其他类似的问题在 SO 上得到了回答 但是这些解决方案对我来说不起作用 我正在使用StackNavigator 这是我的设置App js file e

随机推荐