草庐IT

javascript - d3.scale.category20 对我来说太聪明了

coder 2024-07-25 原文

任何人都可以向我解释为什么这两个表达式返回不同的值...

log1.text(c20(1)); // "#aec7e8"
log2.text(d3.scale.category20()(1)); // "#1f77b4"

...在以下上下文中


工作示例...

    var c20 = d3.scale.category20(),
      col = d3.range(20).map(function(c) {
        return c20(c).replace("#", "0x")
      }),
      log1 = d3.select("#log1"),
      log2 = d3.select("#log2");

    log1.text(c20(1)); // "#aec7e8"
    log2.text(d3.scale.category20()(1)); // "#1f77b4"
    $("#user-agent").text(navigator.userAgent);
#log div {
  display: inline-block;
  margin: 0 0 0 10px;
  background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>

<div id="log">
  <div id="log1"></div>
  <div id="log2"></div>
</div>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title></title>
</head>

<body>
  <div id="container"></div>
  <p id="user-agent"></p>
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
  <div id="log1"></div>
  <div id="log2"></div>
</body>

</html>

我的系统中报告的用户代理是

Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36


我有点明白上面的行为,但这很奇怪......

这是为什么...

// method 1
d3.range(20).map(d3.scale.category20())

0   #1f77b4
1   #aec7e8
2   #ff7f0e
3   #ffbb78
4   #2ca02c
5   #98df8a
6   #d62728
7   #ff9896
8   #9467bd
9   #c5b0d5
10  #8c564b
11  #c49c94
12  #e377c2
13  #f7b6d2
14  #7f7f7f
15  #c7c7c7
16  #bcbd22
17  #dbdb8d
18  #17becf
19  #9edae5

与此不同...

// method 2
d3.range(20).map(function(d, i) {
    return d3.scale.category20()(i);
})  

0   #1f77b4
1   #1f77b4
2   #1f77b4
3   #1f77b4
4   #1f77b4
5   #1f77b4
6   #1f77b4
7   #1f77b4
8   #1f77b4
9   #1f77b4
10  #1f77b4
11  #1f77b4
12  #1f77b4
13  #1f77b4
14  #1f77b4
15  #1f77b4
16  #1f77b4
17  #1f77b4
18  #1f77b4
19  #1f77b4

var c20 = d3.scale.category20(),
  log1 = d3.select("#log1"),
  log2 = d3.select("#log2");

log1.text(c20(1)); // "#aec7e8"
log2.text(d3.scale.category20()(1)); // "#1f77b4"

d3.select("#t1").selectAll(".logs")
  .data(d3.range(20).map(d3.scale.category20()))
  .enter().append("tr").selectAll("td").data(function(d) {
    return [d]
  })
  .enter().append("td")
  .attr("class", "logs")
  .text(function(d, i, j) {
    return [j, d].join("\t")
  })

d3.select("#t2").selectAll(".logs")
  .data(d3.range(20).map(function(d, i) {
    return d3.scale.category20()(i);
  }))
  .enter().append("tr").selectAll("td").data(function(d) {
    return [d]
  })
  .enter().append("td")
  .attr("class", "logs")
  .text(function(d, i, j) {
    return [j, d].join("\t")
  })
#log div {
  display: inline-block;
  margin: 0 0 10px 10px;
  background: #ccc;
}
#t1,
#t2 {
  background: #ccc;
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>

<div id="log">
  <div id="log1"></div>
  <div id="log2"></div>
</div>
<div id="t1"></div>
<div id="t2"></div>

只是为了解释一下,我想使用上面方法 2 的原因是因为我需要将十六进制字符串转换为格式正确的十六进制数字,所以我必须在途中处理域值。实际用例是这样的:

var col = d3.range(20).map(function(c){
        return d3.scale.category20()(c).replace("#", "0x")
    });  

这是行不通的(我仍然不明白为什么不行),这就是我必须这样做的原因:

var c20 = d3.scale.category20(),
    col = d3.range(20).map(function(c){
        return c20(c).replace("#", "0x")
    });

最佳答案

您可以认为调色板在使用过程中“不断增加”。如果您在顶部创建调色板,例如

var palette = d3.scale.category20();

并在迭代中应用调色板不同的值(例如

selection.style('fill', function(d, i) {return palette(i);});

然后在每次调用时,调色板检查它是否已经为该值分配了颜色;如果没有,它会尝试提供一种新颜色(或者如果颜色用完则回收)。

相比之下,如果您在迭代中将值应用到一个新的调色板,它总是只会从那个特定的调色板中提取一个值:

selection.style('fill', function(d, i) {return d3.scale.category20()(i);});

不良结果是所有颜色都相同。

换句话说,d3.scale.category20 不是纯函数;它隐含地跟踪它的状态。它类似于例如使用接受种子的随机数生成,即确定性:您不想在迭代中重新创建它,否则您提取的随机数将始终相同。

这个问题(D3v4 之前)说明了函数式编程的一般值(value),因为预计使用某些值调用的函数将始终仅依赖于提供的参数,这也使测试更容易。

关于javascript - d3.scale.category20 对我来说太聪明了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32422325/

有关javascript - d3.scale.category20 对我来说太聪明了的更多相关文章

  1. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  2. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  3. ruby - 在 Mechanize 中使用 JavaScript 单击链接 - 2

    我有这个:AccountSummary我想单击该链接,但在使用link_to时出现错误。我试过:bot.click(page.link_with(:href=>/menu_home/))bot.click(page.link_with(:class=>'top_level_active'))bot.click(page.link_with(:href=>/AccountSummary/))我得到的错误是:NoMethodError:nil:NilClass的未定义方法“[]” 最佳答案 那是一个javascript链接。Mechan

  4. Ubuntu20.04系统WineHQ7.0安装微信 - 2

    提供3种Ubuntu系统安装微信的方法,在Ubuntu20.04上验证都ok。1.WineHQ7.0安装微信:ubuntu20.04安装最新版微信--可以支持微信最新版,但是适配的不是特别好;比如WeChartOCR.exe报错。2.原生微信安装:linux系统下的微信安装(ubuntu20.04)--微信适配的最好,反应最快,但是微信版本只到2.1.1,版本太老,很多功能都没有。3.深度deepin-wine6安装微信:ubuntu20.04+系统deepin-wine6安装新版微信--综合比较好,当前个人使用此种方法1个月,微信版本3.4;没什么大问题,尚可。一、WineHQ7.0安装微信

  5. javascript - jQuery 的 jquery-1.10.2.min.map 正在触发 404(未找到) - 2

    我看到有关未找到文件min.map的错误消息:GETjQuery'sjquery-1.10.2.min.mapistriggeringa404(NotFound)截图这是从哪里来的? 最佳答案 如果ChromeDevTools报告.map文件的404(可能是jquery-1.10.2.min.map、jquery.min.map或jquery-2.0.3.min.map,但任何事情都可能发生)首先要知道的是,这仅在使用DevTools时才会请求。您的用户不会遇到此404。现在您可以修复此问题或禁用sourcemap功能。修复:获取文

  6. ruby-on-rails - 我将 Rails3 与 tinymce 一起使用。如何呈现用户关闭浏览器javascript然后输入xss? - 2

    我有一个用Rails3编写的站点。我的帖子模型有一个名为“内容”的文本列。在帖子面板中,html表单使用tinymce将“content”列设置为textarea字段。在首页,因为使用了tinymce,post.html.erb的代码需要用这样的原始方法来实现。.好的,现在如果我关闭浏览器javascript,这个文本区域可以在没有tinymce的情况下输入,也许用户会输入任何xss,比如alert('xss');.我的前台会显示那个警告框。我尝试sanitize(@post.content)在posts_controller中,但sanitize方法将相互过滤tinymce样式。例如

  7. ruby - 使用 Selenium WebDriver 启用/禁用 javascript - 2

    出于某种原因,我必须为Firefox禁用javascript(手动,我们按照提到的步骤执行http://support.mozilla.org/en-US/kb/javascript-settings-for-interactive-web-pages#w_enabling-and-disabling-javascript)。使用Ruby的SeleniumWebDriver如何实现这一点? 最佳答案 是的,这是可能的。而是另一种方式。您首先需要查看链接Selenium::WebDriver::Firefox::Profile#[]=

  8. ruby-on-rails - encode_www_form 将空格转换为 + 而不是 %20 - 2

    我正在尝试从使用RubyonRails的散列创建http参数,我尝试使用URI.encode_www_form(params),但这没有正确生成参数。下面是我的哈希值params['Name'.to_sym]='NiaKun'params['AddressLine1'.to_sym]='AddressOne'params['City'.to_sym]='CityName'这个方法把空格转成+,我要的是把空格转成%20我收到"Name=Nia+Kun&AddressLine1=Address+One&City=City+Name"但我需要将此空格转换为%20

  9. ruby - Watir-Webdriver 是否支持点击目标为 javascript 的链接? - 2

    我是Ruby和Watir-Webdriver的新手。我有一套用VBScript编写的站点自动化程序,我想将其转换为Ruby/Watir,因为我现在必须支持Firefox。我发现我真的很喜欢Ruby,而且我正在研究Watir,但我已经花了一周时间试图让Webdriver显示我的登录屏幕。该站点以带有“我同意”区域的“警告屏幕”开头。用户点击我同意并显示登录屏幕。我需要单击该区域以显示登录屏幕(这是同一页面,实际上是一个表单,只是隐藏了)。我整天都在用VBScript这样做:objExplorer.Document.GetElementsByTagName("area")(0).click

  10. ruby - 为什么 split (' ' ) 试图变得(太)聪明? - 2

    我刚刚发现String#split有以下奇怪的行为:"a\tbc\nd".split=>["a","b","c","d"]"a\tbc\nd".split('')=>["a","b","c","d"]"a\tbc\nd".split(//)=>["a\tb","c\nd"]Thesource(来自2.0.0的string.c)超过200行,包含这样一段话:/*L5909*/elseif(rb_enc_asciicompat(enc2)==1){if(RSTRING_LEN(spat)==1&&RSTRING_PTR(spat)[0]==''){split_type=awk;}}后来,在

随机推荐