我正在通过SVG放置Sankey图,但突然在某些未知条件下,其中一条路径显示了一个不应该有的圆圈。
我试图从我的SVG中删除尽可能多的东西,但进一步删除任何东西都无法再现。
在这里,您可以看到我减少的SVG图像。黑色路径元素是有问题的元素。我手动地标记了路径笔触元素应结束的位置,但它以某种方式显示了一个圆,该圆似乎具有与中风宽度相同的半径。
<div style="width: 100%; height: 100%;">
<svg width=100% height=500px>
<g class="sankey-layer">
<g class="link-group">
<path d="M107.61971830985915,30C107.61971830985915,74,107.61971830985915,74,107.61971830985915,118" fill="none" stroke="#000000" stroke-opacity="1" stroke-width="200"></path>
<path d="M251.11267605633802,30C251.11267605633802,192,328.943661971831,192,328.943661971831,354" fill="none" stroke="#00bbff35" stroke-opacity="0.5" stroke-width="71.74647887323944"></path>
<path d="M478.38028169014075,30C478.38028169014075,192,384.7464788732394,192,384.7464788732394,354" fill="none" stroke="#00bbff35" stroke-opacity="0.5" stroke-width="39.859154929577464"></path>
<path d="M542.1549295774647,30C542.1549295774647,192,572.1549295774648,192,572.1549295774648,354" fill="none" stroke="#00bbff35" stroke-opacity="0.5" stroke-width="87.69014084507042"></path>
<path d="M344.8169014084507,30C344.8169014084507,192,452.50704225352115,192,452.50704225352115,354" fill="none" stroke="#00bbff35" stroke-opacity="0.5" stroke-width="95.66197183098592"></path>
<path d="M143.49295774647888,148C143.49295774647888,251,153.49295774647888,251,153.49295774647888,354" fill="none" stroke="#00bbff35" stroke-opacity="0.5" stroke-width="79.71830985915493"></path>
<path d="M409.12773522289996,148C409.12773522289996,251,213.28169014084506,251,213.28169014084506,354" fill="none" stroke="#00bbff35" stroke-opacity="0.5" stroke-width="39.859154929577464"></path>
</g>
</g>
</svg>
</div>
有什么线索来自哪里,我该怎么做才能避免它?
澄清:
路径由D3计算。这不是手动创建的图形,我正在寻找问题的一般解决方案,而不是这个特定示例的解决方案。
I'm putting together a Sankey diagram via SVG but suddenly under some unknown conditions one of the paths show a circle where there shouldn't be any.
I tried to remove as much as possible from the my SVG but removing anything further makes this no longer reproducible.
Here you can see my reduced SVG image. The black path element is the one having the issue. I manually marked where the path stroke element should end but somehow it shows a circle which seems to have the same radius as the stroke width.

<div style="width: 100%; height: 100%;">
<svg width=100% height=500px>
<g class="sankey-layer">
<g class="link-group">
<path d="M107.61971830985915,30C107.61971830985915,74,107.61971830985915,74,107.61971830985915,118" fill="none" stroke="#000000" stroke-opacity="1" stroke-width="200"></path>
<path d="M251.11267605633802,30C251.11267605633802,192,328.943661971831,192,328.943661971831,354" fill="none" stroke="#00bbff35" stroke-opacity="0.5" stroke-width="71.74647887323944"></path>
<path d="M478.38028169014075,30C478.38028169014075,192,384.7464788732394,192,384.7464788732394,354" fill="none" stroke="#00bbff35" stroke-opacity="0.5" stroke-width="39.859154929577464"></path>
<path d="M542.1549295774647,30C542.1549295774647,192,572.1549295774648,192,572.1549295774648,354" fill="none" stroke="#00bbff35" stroke-opacity="0.5" stroke-width="87.69014084507042"></path>
<path d="M344.8169014084507,30C344.8169014084507,192,452.50704225352115,192,452.50704225352115,354" fill="none" stroke="#00bbff35" stroke-opacity="0.5" stroke-width="95.66197183098592"></path>
<path d="M143.49295774647888,148C143.49295774647888,251,153.49295774647888,251,153.49295774647888,354" fill="none" stroke="#00bbff35" stroke-opacity="0.5" stroke-width="79.71830985915493"></path>
<path d="M409.12773522289996,148C409.12773522289996,251,213.28169014084506,251,213.28169014084506,354" fill="none" stroke="#00bbff35" stroke-opacity="0.5" stroke-width="39.859154929577464"></path>
</g>
</g>
</svg>
</div>
Any clue where this comes from and what I can do to avoid it?
Clarification:
The paths are computed by d3. It's not a manually created graphic and I'm looking for a general solution to the problem, not a solution for this particular example.
发布评论
评论(3)
我将第一个路径更改为
&lt;路径d =“ m107.62,30l107.62,118” fill =“ none” stroke =“#000000” stroke-opacity =“ 1” stroke-witth =“ 200”&gt; &lt;/path&gt;
。我通过将其加载到Illustrator来解决。我不是100%确定问题是什么,但是也许比我聪明的人会弄清楚。 SVG的数学伤害了我的大脑。
I changed the first path to
<path d="M107.62,30L107.62,118" fill="none" stroke="#000000" stroke-opacity="1" stroke-width="200"></path>
. I worked this out by loading it in to Illustrator.I'm not 100% sure what the issue was, but maybe someone smarter than me will figure it out. The maths of SVGs hurts my brain.
通常,您应该报告的浏览器与浏览器相关的错误。
作为“后处理”解决方法,您可以使用我曾经创建的此助手将平面曲线转换为
l
命令。(基于 jarek foksa 路径数据polyfill )
修复了边缘问题。
还可以工作curveto命令
d =“ M107.6 30 C 107.6 74 107.6 118 107.6 118”
[x2,y2] = [x3,y3]
d =“ M107.6 30 C 107.6 118 107.6 118 107.6 118”
[x1,y1] = [x2,y2] = [x3,y3]
Apperently a browser related bug you should report.
As a "post-processing" workaround you could use this helper I've once created to convert flat curves to
L
commands.(based on path data polyfill by Jarek Foksa)
Fixed the issue in edge.
Also working curveto commands
d="M107.6 30 C 107.6 74 107.6 118 107.6 118"
[x2,y2] = [x3,y3]
d="M107.6 30 C 107.6 118 107.6 118 107.6 118"
[x1,y1] = [x2,y2] = [x3,y3]
解决方案
我第一个解决此问题的解决方法是为我的链路路径的预期界限(开始和结束)定义剪辑路径。这样,伪像只是简单地剪掉的,看不到问题:
此代码与上下文有点不合时宜,但我将其包括在内,只是为了给出解决方案的想法。它来自带有垂直Sankey的Svelte应用程序,我简化了代码。
这个解决方法实际上效果很好,但感觉很不错。我想要一个“适当的”解决方案。
@herrstrietzel提出的解决方案( https://stackoverflow.com/a/a/72588392/22230045 )似乎是技术上的更正确的解决方法,但我无法摆脱它仍然感觉像是一个骇人听闻的解决方法。
解决方案
在寻找解决方案时,我遇到了这篇博客文章: https:https:https: //observablehq.com/@enjalot/weird-sankey-links
当问题上的博客文章关注外观略有不同,我敢肯定这是完全相同的问题我正在经历。
从某种意义上说,我觉得这里的根本问题是对路径元素的滥用。设置填充到
无
并增加绘制线路绘制线路的情况下,当线短时,似乎无法正常工作。博客文章建议改为绘制自定义的Bézier曲线。
这消除了对中风属性的需求,相反,我们可以使用普通填充物。这对我来说是一个适当的解决方案。让我们看一下代码。
在这个问题之前,我并没有真正看一下Sankey图的图形侧。
在尝试理解博客文章中提出的解决方案(我需要更改代码以垂直而不是水平工作)时,我努力地完整地绘制了坐标是指的是什么。
D3文档对此并没有真正的帮助。
在这里,我为自己制作的信息图形:
博客文章中的代码使用略有不同的坐标命名。我对此进行了调整,添加了一些评论,并试图简化它。
这样做的是,它绘制了链接轮廓的路径。
将我的代码简化为:
调整Sankey的垂直绘图
最后,我调整了代码以垂直而不是水平工作:
现在可以产生这种绝对良好的工作桑基情节:
我对与SVGS和D3合作有了很多了解。我希望该解决方案将来对其他人有所帮助。
Workarounds
My first workaround to resolve this issue was to also define a clip path for the expected bounds (start and end) of my link path. This way the artifact is simply clipped and no issue is visible:
This code is a bit out of context but I included it just to give an idea of the solution. It's from a Svelte application with a vertical Sankey and I reduced the code for brevity.
This workaround actually works great but it feels so wrong. I wanted a "proper" solution.
The solution proposed by @herrstrietzel (https://stackoverflow.com/a/72588392/2230045) seems to be a technically more correct workaround but I can't shake off that it still feels like a hacky workaround.
Solution
While looking for solutions I came across this blog post: https://observablehq.com/@enjalot/weird-sankey-links
While the issue the blog post focuses on looks slightly different, I'm sure it's the exact same issue I'm experiencing.
In some sense, I feel like the underlying issue here is a misuse of the path element. Setting fill to
none
and increasing the stroke width to draw the line seems to not work properly when the line is shorter than the stroke width.The blog post proposes to draw custom Bézier curves instead.
This removes the need for the stroke property and instead we can just use the normal fill. This feels like a proper solution to me. Let's look into the code.
Before this question I did not really look into the graphical side of Sankey diagrams.
While trying to understand the solution proposed in the blog post (I need to change the code to work vertically instead of horizontally), I struggled to fully graphs what coordinates are referring to what.
The d3 docs are not really helpful on that.
Here an info graphic I made for myself:
The code from the blog post uses a slightly different coordinate naming. I adapted this, added some comments and tried to simplify it.
What this does is, that it draws a path of the outline of the link.
Which reduces my code to:
Adjust for Vertical Plotting of Sankey
Finally, I adjusted the code to work vertically instead of horizontally:
Which now yields this absolutely fine working Sankey plot:
I gained quite some insight into working with SVGs and d3 with this. I hope the solution helps someone else in the future.