Plotly:在值和单位之间添加 space(荣誉 SI)
Plotly: add space between value and units (honor SI)
根据The International System of Units:
The value of a quantity is written as a number followed by a space (representing a multiplication sign) and a unit symbol; e.g., 21 kg, 22 K.
我正在尝试创建一个纪念 space 的情节,但我似乎做不到。 Plotly 将在数量和单位符号之间不添加 space(在本例中为 MN,添加 mega 前缀后):
const data = [
{
x: ['A', 'B', 'C'],
y: [20000000, 14000000, 23000000],
type: 'bar',
}
];
const layout = {
yaxis: {
title: 'Force',
ticksuffix: 'N',
}
}
Plotly.newPlot('plotDiv', data, layout);
<head>
<script src='https://cdn.plot.ly/plotly-2.6.3.min.js'></script>
</head>
<body>
<div id='plotDiv'></div>
</body>
如何在数量和单位符号之间添加 space?
理想情况下:
- 它应该适用于任何前缀(包括无前缀)
- space 应同时在 y 轴和悬停标签中表示
这有点复杂。我尝试通过 plotly API 查找,但找不到解决方案。然而,下面的代码只是生成了它自己的工具提示。
注意添加的 css 到 head 标签。
<html>
<head>
<script src='https://cdn.plot.ly/plotly-2.6.3.min.js'></script>
<!-- Add the css to hide the plotly tooltip and create our own -->
<style>
/* hide plotly tooltip - we'll still use it for position and data */
.main-svg g.hoverlayer g.hovertext {
opacity: 0;
}
/* Style our own tooltip - you can play with the values as you wish */
#tooltip {
display: flex;
justify-content: center;
align-items: center;
min-width: 80px;
height: 20px;
background: #006eb6;
position: absolute;
z-index: 10;
top: 0;
margin-left: 10px;
font-size: 10px;
color: white;
border: 1px solid white;
border-left: 0 solid white;
}
/* create the triangle */
#tooltip:before {
content: "";
width: 0;
height: 0;
left: -10px;
top: 0;
position: absolute;
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
border-right: 10px solid #006eb6;
}
</style>
</head>
<body>
<div id='plotDiv'></div>
</body>
<script>
const data = [
{
x: ['A', 'B', 'C'],
y: [20000000, 14000000, 23000000],
type: 'bar',
}
];
const layout = {
yaxis: {
title: 'Force',
ticksuffix: 'N'
//ticksuffix: ' N'
}
}
Plotly.newPlot('plotDiv', data, layout);
// add the spacing to the axes
const yaxes = document.querySelectorAll('.ytick text')
for(let yaxis of yaxes) {
yaxis.innerHTML = yaxis.innerHTML.replace(/(\d+)/g, (_, num) => num + ' ')
}
// tooltip starts here
// create a new tool tip - add it to body and hide it on display
const tooltip = document.createElement('div')
tooltip.setAttribute('id', 'tooltip')
tooltip.style.display = "none"
document.body.appendChild(tooltip)
// add mousemove event to body to override plotly hover
// get the bounding box of each bar in the chart
const underbars = document.getElementsByClassName('point')
const positions = []
for(let underbar of underbars) {
positions.push(underbar.getBoundingClientRect())
}
// add event to display tooltip when mouse cursor is inside bar
document.body.onmousemove = evt => {
const x = evt.clientX
const y = evt.clientY
// check if cursor falls inside bar
let position = null;
positions.forEach(pi => {
pi.left = pi.left + window.scrollX
pi.top = pi.top + window.scrollY
if(x >= pi.left && x <= pi.left + pi.width && y >= pi.top && y <= pi.top + pi.height) {
position = pi
}
})
// if it does, get the data from plotly tool tip and add it to our own
if(position) {
// get position of tooltip
const hover_element = document.querySelector('.main-svg g.hoverlayer g.hovertext')
if(!hover_element) {
return
}
const transform = hover_element.getAttribute('transform').replaceAll(' ', '')
// get the text from plotly tooltip and set it to our tooltip adding a space
const text = document.querySelector('.main-svg g.hoverlayer g.hovertext text').innerHTML
tooltip.innerHTML = text.replace(/(\d+)/g, (_, num) => num + ' ')
// get position of our plotly tooltip - add px so its compatible with css
tooltip.style.transform = transform.replace(/(\d+\.\d+)/g, (_, num) => num + 'px')
// have to add scroll and position container offset - this allows the chart to
// be rendered anywhere on screen. Can +/- px's for finer control of tooltip
const cp = document.querySelector('.main-svg').getBoundingClientRect()
tooltip.style.marginTop = window.scrollY + cp.top
tooltip.style.marginLeft = window.scrollX + cp.left
// display tooltip
tooltip.style.display = 'flex'
}
else {
// hide tooltip on exit
tooltip.style.display = "none"
}
}
</script>
<\html>
也许更熟悉 Plotly 的人会插话。否则,请告诉我是否可以添加任何说明。
我将
添加到 ticksuffix 和 hoverformat:".1f"
,结果可能就是您想要的。注意:
是 space 的转义码。
我使用 hoverformat 来避免默认格式(即 12000000 在悬停文本上变为 12M)。如果需要,它打开了进一步操纵悬停文本的可能性。
编辑
我修改了代码,得到的结果更符合OP的要求。
const data = [
{
x: ['A', 'B', 'C'],
y: [20000000, 14000000, 12300000],
type: 'bar',
}
];
const average = (arr) => arr.reduce((a, b) => a + b, 0) / arr.length;
const divby1e6 = (arr) => arr.map((a) => a / 1000000);
let meany = average(data[0].y);
let suffix = "N";
if (meany > 1e6) {
// compute new y, prep suffix
suffix = " M" + suffix;
data[0].y = divby1e6(data[0].y);
}
else {
// just in case
}
const layout = {
yaxis: {
title: 'Force',
hoverformat: ".3f", //specify decimal digits
ticksuffix: suffix,
tickformat: '.3f'
}
}
Plotly.newPlot('plotDiv', data, layout);
<head>
<script src='https://cdn.plot.ly/plotly-2.6.3.min.js'></script>
</head>
<body>
<div id='plotDiv'></div>
</body>
根据The International System of Units:
The value of a quantity is written as a number followed by a space (representing a multiplication sign) and a unit symbol; e.g., 21 kg, 22 K.
我正在尝试创建一个纪念 space 的情节,但我似乎做不到。 Plotly 将在数量和单位符号之间不添加 space(在本例中为 MN,添加 mega 前缀后):
const data = [
{
x: ['A', 'B', 'C'],
y: [20000000, 14000000, 23000000],
type: 'bar',
}
];
const layout = {
yaxis: {
title: 'Force',
ticksuffix: 'N',
}
}
Plotly.newPlot('plotDiv', data, layout);
<head>
<script src='https://cdn.plot.ly/plotly-2.6.3.min.js'></script>
</head>
<body>
<div id='plotDiv'></div>
</body>
如何在数量和单位符号之间添加 space?
理想情况下:
- 它应该适用于任何前缀(包括无前缀)
- space 应同时在 y 轴和悬停标签中表示
这有点复杂。我尝试通过 plotly API 查找,但找不到解决方案。然而,下面的代码只是生成了它自己的工具提示。
注意添加的 css 到 head 标签。
<html>
<head>
<script src='https://cdn.plot.ly/plotly-2.6.3.min.js'></script>
<!-- Add the css to hide the plotly tooltip and create our own -->
<style>
/* hide plotly tooltip - we'll still use it for position and data */
.main-svg g.hoverlayer g.hovertext {
opacity: 0;
}
/* Style our own tooltip - you can play with the values as you wish */
#tooltip {
display: flex;
justify-content: center;
align-items: center;
min-width: 80px;
height: 20px;
background: #006eb6;
position: absolute;
z-index: 10;
top: 0;
margin-left: 10px;
font-size: 10px;
color: white;
border: 1px solid white;
border-left: 0 solid white;
}
/* create the triangle */
#tooltip:before {
content: "";
width: 0;
height: 0;
left: -10px;
top: 0;
position: absolute;
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
border-right: 10px solid #006eb6;
}
</style>
</head>
<body>
<div id='plotDiv'></div>
</body>
<script>
const data = [
{
x: ['A', 'B', 'C'],
y: [20000000, 14000000, 23000000],
type: 'bar',
}
];
const layout = {
yaxis: {
title: 'Force',
ticksuffix: 'N'
//ticksuffix: ' N'
}
}
Plotly.newPlot('plotDiv', data, layout);
// add the spacing to the axes
const yaxes = document.querySelectorAll('.ytick text')
for(let yaxis of yaxes) {
yaxis.innerHTML = yaxis.innerHTML.replace(/(\d+)/g, (_, num) => num + ' ')
}
// tooltip starts here
// create a new tool tip - add it to body and hide it on display
const tooltip = document.createElement('div')
tooltip.setAttribute('id', 'tooltip')
tooltip.style.display = "none"
document.body.appendChild(tooltip)
// add mousemove event to body to override plotly hover
// get the bounding box of each bar in the chart
const underbars = document.getElementsByClassName('point')
const positions = []
for(let underbar of underbars) {
positions.push(underbar.getBoundingClientRect())
}
// add event to display tooltip when mouse cursor is inside bar
document.body.onmousemove = evt => {
const x = evt.clientX
const y = evt.clientY
// check if cursor falls inside bar
let position = null;
positions.forEach(pi => {
pi.left = pi.left + window.scrollX
pi.top = pi.top + window.scrollY
if(x >= pi.left && x <= pi.left + pi.width && y >= pi.top && y <= pi.top + pi.height) {
position = pi
}
})
// if it does, get the data from plotly tool tip and add it to our own
if(position) {
// get position of tooltip
const hover_element = document.querySelector('.main-svg g.hoverlayer g.hovertext')
if(!hover_element) {
return
}
const transform = hover_element.getAttribute('transform').replaceAll(' ', '')
// get the text from plotly tooltip and set it to our tooltip adding a space
const text = document.querySelector('.main-svg g.hoverlayer g.hovertext text').innerHTML
tooltip.innerHTML = text.replace(/(\d+)/g, (_, num) => num + ' ')
// get position of our plotly tooltip - add px so its compatible with css
tooltip.style.transform = transform.replace(/(\d+\.\d+)/g, (_, num) => num + 'px')
// have to add scroll and position container offset - this allows the chart to
// be rendered anywhere on screen. Can +/- px's for finer control of tooltip
const cp = document.querySelector('.main-svg').getBoundingClientRect()
tooltip.style.marginTop = window.scrollY + cp.top
tooltip.style.marginLeft = window.scrollX + cp.left
// display tooltip
tooltip.style.display = 'flex'
}
else {
// hide tooltip on exit
tooltip.style.display = "none"
}
}
</script>
<\html>
也许更熟悉 Plotly 的人会插话。否则,请告诉我是否可以添加任何说明。
我将
添加到 ticksuffix 和 hoverformat:".1f"
,结果可能就是您想要的。注意:
是 space 的转义码。
我使用 hoverformat 来避免默认格式(即 12000000 在悬停文本上变为 12M)。如果需要,它打开了进一步操纵悬停文本的可能性。
编辑
我修改了代码,得到的结果更符合OP的要求。
const data = [
{
x: ['A', 'B', 'C'],
y: [20000000, 14000000, 12300000],
type: 'bar',
}
];
const average = (arr) => arr.reduce((a, b) => a + b, 0) / arr.length;
const divby1e6 = (arr) => arr.map((a) => a / 1000000);
let meany = average(data[0].y);
let suffix = "N";
if (meany > 1e6) {
// compute new y, prep suffix
suffix = " M" + suffix;
data[0].y = divby1e6(data[0].y);
}
else {
// just in case
}
const layout = {
yaxis: {
title: 'Force',
hoverformat: ".3f", //specify decimal digits
ticksuffix: suffix,
tickformat: '.3f'
}
}
Plotly.newPlot('plotDiv', data, layout);
<head>
<script src='https://cdn.plot.ly/plotly-2.6.3.min.js'></script>
</head>
<body>
<div id='plotDiv'></div>
</body>