gpt4 book ai didi

javascript - Plotly - 根据值隐藏悬停工具提示上的数据?

转载 作者:行者123 更新时间:2023-12-04 11:35:31 25 4
gpt4 key购买 nike

当我将鼠标悬停在堆积折线图上时,它会显示不在范围内的所有线条的零。有没有办法隐藏这些值而不是向悬停工具添加噪音?
最小示例

Plotly.newPlot('test', [{
line: { shape : 'vh' },
stackgroup: '1',
x: [1, 2],
y: [1, 1],
}, {
line: { shape : 'vh' },
stackgroup: '1',
x: [3, 4],
y: [2, 2],
}, {
line: { shape : 'vh' },
stackgroup: '1',
x: [3, 4, 5, 6],
y: [3, 3, 3, 3],
}], {
hovermode: 'x unified',
width: '100%',
});
作为 jsfiddle和图像:
Minimal example - stacked plotly graph showing legend noise
语境
我有一个时间序列图,拉伸(stretch) ~5yr,包含每条跨度为 6-12mo 的单条线。 Plotly 用零填充每一行,这使得悬停工具非常嘈杂。
Plotly hover graph
我想隐藏每个 x 轴日期的“0 小时”条目,方法是确保 Plotly 不会对行进行 0 填充,或者通过配置工具提示来动态隐藏值。

最佳答案

TL; 博士
这是最终产品,如下所示。看看我的逻辑如何使用 CSS 自定义属性来对抗 Plotly 的持久性。不幸的是,在深入研究 Plotly 的文档一段时间后,似乎没有使用 Plotly 的函数实现这一目标的简单或原生方法,但这不会阻止我们利用我们的知识来解决其生态系统的自然法则.

const testPlot = document.getElementById('test');

Plotly.newPlot('test', [{
line: { shape : 'vh' },
stackgroup: '1',
x: [1, 2, null, null],
y: [1, 1, null, null],
}, {
line: { shape : 'vh' },
stackgroup: '1',
x: [3, 4, null, null],
y: [2, 2, null, null],
}, {
line: { shape : 'vh' },
stackgroup: '1',
x: [3, 4, 5, 6],
y: [3, 3, 3, 3],
}], {
hovermode: 'x unified',
width: '100%'
});

const addPxToTransform = transform => 'translate(' + transform.replace(/[^\d,.]+/g, '').split(',').map(e => e + 'px').join(',') + ')';

['plotly_hover', 'plotly_click', 'plotly_legendclick', 'plotly_legenddoubleclick'].forEach(trigger => {
testPlot.on(trigger, function(data) {
if (document.querySelector('.hoverlayer > .legend text.legendtext')) {
const legend = document.querySelector('.hoverlayer > .legend');
legend.style.setProperty('--plotly-legend-transform', addPxToTransform(legend.getAttribute('transform')));
const legendTexts = Array.from(document.querySelectorAll('.hoverlayer > .legend text.legendtext'));
const legendTextGroups = Array.from(document.querySelectorAll('.hoverlayer > .legend text.legendtext')).map(text => text.parentNode);
const transformValues = [];
legendTexts.filter(label => (transformValues.push(addPxToTransform(label.parentNode.getAttribute('transform'))), label.textContent.includes(' : 0'))).forEach(zeroValue => zeroValue.parentNode.classList.add('zero-value'));
legendTextGroups.filter(g => !g.classList.contains('zero-value')).forEach((g,i) => g.style.setProperty('--plotly-transform', transformValues[i]));
const legendBG = document.querySelector('.hoverlayer > .legend > rect.bg');
legendBG.style.setProperty('--plotly-legend-bg-height', Math.floor(legendBG.nextElementSibling.getBBox().height + 10) + 'px');
}
});
});
.hoverlayer > .legend[style*="--plotly-legend-transform"] {
transform: var(--plotly-legend-transform) !important;
}
.hoverlayer > .legend > rect.bg[style*="--plotly-legend-bg-height"] {
height: var(--plotly-legend-bg-height) !important;
}
.hoverlayer > .legend [style*="--plotly-transform"] {
transform: var(--plotly-transform) !important;
}
.hoverlayer > .legend .zero-value {
display: none !important;
}
<div id="test"></div>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>

完整的解释
这个真的让我循环了(没有双关语)。我搜索了 Plotly 文档才发现,虽然它们非常全面,但它们并没有提供像您这样的人在定制方面所希望的所有灵活性。他们确实有一个页面,上面有关于他们 Plotly JS Filters 的基本信息。 ,包含一个基本示例,但它实际上不会像您希望的那样从您的图例中删除任何点。
接下来,我走上了设置 mousemove的路线。您将绘图分配给的 div 上的事件监听器。这开始起作用了,但在我的风格和那些 Plotly 似乎坚持使用的风格之间有很多闪烁。这让我注意到 Plotly 的脚本编写非常持久,这在后来派上用场。接下来,我尝试了类似的东西 MutationObserver因为它应该更快,但唉,更多的是相同的。
在这一点上,我重新挖掘了 Plotly 文档,并在他们的自定义内置 JS Event Handlers 上找到了一个页面。 .我开始使用 plotly_hover事件,我正在取得进展。此事件的运行频率远低于 mousemove所以它对浏览器来说不那么累人,而且它只在 Plotly JS 事件上运行,所以它真的只在你需要的时候运行,这样很方便。但是,我仍然遇到了一些闪烁。
我意识到我可以注入(inject)我自己的样式,但是 Plotly 很快就会覆盖我试图覆盖的任何属性。如果我覆盖属性,它会将其改回。如果我删除了一个零值图例键,它会刷新图例以重新包含它。我必须要有创意。当我发现 Plotly 不会覆盖我添加到图例键或其祖先的自定义 CSS 属性时,我终于开始取得重大进展。利用这一点以及我已经从 Plotly 构建的 SVG 元素中获得的属性值,我能够相应地操纵它们。
还有一些棘手的问题,但我设法把它们全部解决了。我创建了所有原始数组 transform所有图例键的属性值,包括那些具有零值的键,然后在隐藏零值键之后,我遍历那些仍然可见的键,并使用我提到的自定义 CSS 属性重置它们的转换属性。如果我尝试内联添加 CSS,Plotly 会很快被覆盖,因此我使用了单独的样式表。 transform存储在 SVG 属性中的值没有 px在它们中,所以我编写了一个快速的正则表达式函数来清理它,然后在设置键上的自定义属性之前将这些更新的值推送到数组。即使迈出了这一步,我还没有走出困境。这允许我隐藏零值键并重新组织可见键以再次堆叠在顶部(摆脱尴尬的空白)但图例容器本身和图例框仍然有一点闪烁还是原来的高度。
为了解决图例的闪烁位置,我对其进行了与按键类似的处理。在我的任何其他逻辑之前,我设置了图例的 transform属性使用 CSS 自定义属性来保持它的持久性,即使 Plotly 试图适应我的更改并覆盖我的样式。然后,为了解决高度问题,在我所有其他逻辑的最后,我使用自定义 CSS 属性(您猜对了)重新计算了背景(一个单独的矩形元素)的高度。我们也不能使用 offsetHeightclientHeight在 SVG 元素上,所以我使用边界框计算高度 elem.getBBox().height .
最后一个变化——我还注意到,即使我的风格在大多数情况下都有效,如果你点击 Plotly Canvas ,Plotly 似乎做了一个快速重置,这如何抵消我的风格的唯一解释是是一个单独的事件,不会触发我的更改。我重新访问了文档并添加了一些其他被触发到事件处理程序列表的监听器。
为了代码干净,我将所有处理程序名称放入数组并使用 forEach() 循环遍历它们。 .我支持的事件处理程序是 plotly_hover , plotly_click , plotly_legendclick , 和 plotly_legenddoubleclick .
这是成品:

const testPlot = document.getElementById('test');

Plotly.newPlot('test', [{
line: { shape : 'vh' },
stackgroup: '1',
x: [1, 2, null, null],
y: [1, 1, null, null],
}, {
line: { shape : 'vh' },
stackgroup: '1',
x: [3, 4, null, null],
y: [2, 2, null, null],
}, {
line: { shape : 'vh' },
stackgroup: '1',
x: [3, 4, 5, 6],
y: [3, 3, 3, 3],
}], {
hovermode: 'x unified',
width: '100%'
});

const addPxToTransform = transform => 'translate(' + transform.replace(/[^\d,.]+/g, '').split(',').map(e => e + 'px').join(',') + ')';

['plotly_hover', 'plotly_click', 'plotly_legendclick', 'plotly_legenddoubleclick'].forEach(trigger => {
testPlot.on(trigger, function(data) {
if (document.querySelector('.hoverlayer > .legend text.legendtext')) {
const legend = document.querySelector('.hoverlayer > .legend');
legend.style.setProperty('--plotly-legend-transform', addPxToTransform(legend.getAttribute('transform')));
const legendTexts = Array.from(document.querySelectorAll('.hoverlayer > .legend text.legendtext'));
const legendTextGroups = Array.from(document.querySelectorAll('.hoverlayer > .legend text.legendtext')).map(text => text.parentNode);
const transformValues = [];
legendTexts.filter(label => (transformValues.push(addPxToTransform(label.parentNode.getAttribute('transform'))), label.textContent.includes(' : 0'))).forEach(zeroValue => zeroValue.parentNode.classList.add('zero-value'));
legendTextGroups.filter(g => !g.classList.contains('zero-value')).forEach((g,i) => g.style.setProperty('--plotly-transform', transformValues[i]));
const legendBG = document.querySelector('.hoverlayer > .legend > rect.bg');
legendBG.style.setProperty('--plotly-legend-bg-height', Math.floor(legendBG.nextElementSibling.getBBox().height + 10) + 'px');
}
});
});
.hoverlayer > .legend[style*="--plotly-legend-transform"] {
transform: var(--plotly-legend-transform) !important;
}
.hoverlayer > .legend > rect.bg[style*="--plotly-legend-bg-height"] {
height: var(--plotly-legend-bg-height) !important;
}
.hoverlayer > .legend [style*="--plotly-transform"] {
transform: var(--plotly-transform) !important;
}
.hoverlayer > .legend .zero-value {
display: none !important;
}
<div id="test"></div>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>

关于javascript - Plotly - 根据值隐藏悬停工具提示上的数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67077685/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com