用于绘图指标图的表针

问题描述 投票:0回答:2

我目前有一个指标图(仪表),其中的值通过深蓝色中心到达的距离来显示。然而,这对我来说看起来有点奇怪,所以我想将其更改为有一个从中心到值的指针/指针,就像速度计一样。这是我当前的代码:

import plotly.graph_objects as go
fig = go.Figure(go.Indicator(
    mode = "gauge+number",
    number = {'suffix': "% match", 'font': {'size': 50}},
    value = 80,
    domain = {'x': [0,1], 'y': [0,1]},
    gauge = {
        'axis': {'range': [None, 100], 'tickwidth': 1, 'tickcolor': "darkblue"},
        'bar': {'color': "darkblue"},
        'bgcolor': "white",
        'borderwidth': 2,
        'bordercolor': "gray",
        'steps': [
            {'range': [0, 33], 'color': 'red'},
            {'range': [33, 66], 'color': 'yellow'},
            {'range': [66,100], 'color': 'green'}],
        }))

fig.update_layout(font = {'color': "black", 'family': "Arial"})

fig.show()
python plotly
2个回答
6
投票

我的建议是添加一个覆盖指标图表的箭头注释。

通过将图表的范围设置为 [-1,1] x [0,1],我们基本上创建了一个箭头所在的新坐标系,我们可以近似箭头应该到达的位置,以便对应于指标图表上的值。这也将确保点 (0,0) 位于图表的中心,这很方便,因为这将是箭头的端点之一。

添加箭头注释时,

ax
ay
是箭头尾部的坐标,因此我们希望它位于图表的中间,即
ax=0
ay=0
。我将箭头笔直向上放置,以显示指标图表相对于浏览器窗口的图表的半径约为 0.9 个单位。这对您来说可能会有所不同。

import plotly.graph_objects as go

fig = go.Figure(go.Indicator(
    mode = "gauge+number",
    number = {'suffix': "% match", 'font': {'size': 50}},
    value = 80,
    domain = {'x': [0,1], 'y': [0,1]},
    gauge = {
        'axis': {'range': [None, 100], 'tickwidth': 1, 'tickcolor': "darkblue"},
        'bar': {'color': "darkblue"},
        'bgcolor': "white",
        'borderwidth': 2,
        'bordercolor': "gray",
        'steps': [
            {'range': [0, 33], 'color': 'red'},
            {'range': [33, 66], 'color': 'yellow'},
            {'range': [66,100], 'color': 'green'}],
        }))

fig.update_layout(
    font={'color': "black", 'family': "Arial"},
    xaxis={'showgrid': False, 'range':[-1,1]},
    yaxis={'showgrid': False, 'range':[0,1]},
    # plot_bgcolor='rgba(0,0,0,0)'
    )

## by setting the range of the layout, we are effectively adding a grid in the background
## and the radius of the gauge diagram is roughly 0.9 when the grid has a range of [-1,1]x[0,1]

fig.add_annotation(
    ax=0,
    ay=0,
    axref='x',
    ayref='y',
    x=0,
    y=0.9,
    xref='x',
    yref='y',
    showarrow=True,
    arrowhead=3,
    arrowsize=1,
    arrowwidth=4
    )

fig.show()

现在,虽然我们可以通过反复试验来找到箭头应该结束的位置,但这是一个真正的 hacky 解决方案,根本无法推广。

对于接下来的步骤,我建议您为浏览器窗口大小选择一个长宽比,使指标图表尽可能接近圆形(例如,极端的长宽比将使您的指标图表更加椭圆,我正在制作一个简单假设指标图表是一个完美的圆)。

因此,假设指标图表大致是一个半径 ≈ 0.9 的圆(在我的情况下,您的半径可能不同),我们可以使用极坐标找到圆的 x 和 y 坐标:

x = r*cos(θ)
 y = r*sin(θ)
。请注意,此公式仅适用于以 (0,0) 为中心的圆,这就是我们在此时将图表居中的原因。

由于指示器上的值在 0-100 的范围内为 80,因此我们是 180 度旋转角度的 80/100,结果为

180 degrees*(80/100) = 144 degrees
。所以你从左下角顺时针旋转144度,或者从右下角逆时针旋转36度。

插入电源,我们得到

x = 0.9*cos(36 degrees) = 0.72811529493
y = 0.9*sin(36 degrees) = 0.52900672706
。更新注释:

fig.add_annotation(
    ax=0,
    ay=0,
    axref='x',
    ayref='y',
    x=0.72811529493,
    y=0.52900672706,
    xref='x',
    yref='y',
    showarrow=True,
    arrowhead=3,
    arrowsize=1,
    arrowwidth=4
    )

我们得到以下图像:

所以这非常接近,但不是一门精确的科学。对于我的浏览器窗口,我们将角度稍微调整到 40 度。重复相同的过程

x = 0.9*cos(40 degrees) = 0.6894399988
y = 0.9*cos(40 degrees) = 0.57850884871
,并更新注释坐标,我得到以下图表:

为了使图表更漂亮,我们现在可以删除图表中箭头注释的刻度标签,并将背景设置为透明。为了让这个方法更容易调整,我制作了

theta
r
变量。

from numpy import radians, cos, sin
import plotly.graph_objects as go

fig = go.Figure(go.Indicator(
    mode = "gauge+number",
    number = {'suffix': "% match", 'font': {'size': 50}},
    value = 80,
    domain = {'x': [0,1], 'y': [0,1]},
    gauge = {
        'axis': {'range': [None, 100], 'tickwidth': 1, 'tickcolor': "darkblue"},
        'bar': {'color': "darkblue"},
        'bgcolor': "white",
        'borderwidth': 2,
        'bordercolor': "gray",
        'steps': [
            {'range': [0, 33], 'color': 'red'},
            {'range': [33, 66], 'color': 'yellow'},
            {'range': [66,100], 'color': 'green'}],
        }))

fig.update_layout(
    font={'color': "black", 'family': "Arial"},
    xaxis={'showgrid': False, 'showticklabels':False, 'range':[-1,1]},
    yaxis={'showgrid': False, 'showticklabels':False, 'range':[0,1]},
    plot_bgcolor='rgba(0,0,0,0)'
    )

## by setting the range of the layout, we are effectively adding a grid in the background
## and the radius of the gauge diagram is roughly 0.9 when the grid has a range of [-1,1]x[0,1]

theta = 40
r= 0.9
x_head = r * cos(radians(theta))
y_head = r * sin(radians(theta))

fig.add_annotation(
    ax=0,
    ay=0,
    axref='x',
    ayref='y',
    x=x_head,
    y=y_head,
    xref='x',
    yref='y',
    showarrow=True,
    arrowhead=3,
    arrowsize=1,
    arrowwidth=4
    )

fig.show()


0
投票

我对上面给出的答案做了一些细微的调整。这些调整是:

  1. 根据数值任意角度
  2. 添加固定的 x/y 轴缩放,以便结果显示在浏览器和设备之间保持一致。
  3. 配置箭头,使其不必从图形中心开始。

在我的例子中,

value
代表百分比:

value = 0.06
fig = go.Figure(
    go.Indicator(
        mode='gauge+number',
        value=100*value,
        number={'suffix': "%"},
        domain = {'x': [0, 1], 'y': [0, 1]},
        gauge = {
            'axis': {'range': [None, 100], 'tickwidth': 1},
            'bar': {'color': "lightgray"},
            'borderwidth': 2,
            'steps': [
                {'range': [0, 75], 'color': 'red'},
                {'range': [75, 95], 'color': 'yellow'},
                {'range': [95 ,100], 'color': 'green'}],
        }
    )
)

fig.update_layout(
    margin=dict(t=20, b=10, l=10, r=10),
    plot_bgcolor='rgba(0,0,0,0)',
    xaxis={'showgrid': False, 'showticklabels': False, 'range':[-1,1]},
    yaxis={'showgrid': False, 'showticklabels': False, 'range':[0,1]},
)

fig.update_yaxes(
    scaleanchor="x",
    scaleratio=1,
)

angle = np.pi*(1-value[![enter image description here][1]][1])
unit = np.array([np.cos(angle), np.sin(angle)])
ro = 0.8
ri = 0.3
ax, ay = ri*unit
x, y = ro*unit
fig.add_annotation(
    ax=ax,
    ay=ay,
    axref='x',
    ayref='y',
    x=x,
    y=y,
    xref='x',
    yref='y',
    showarrow=True,
    arrowhead=3,
    arrowsize=1,
    arrowwidth=4
    )
© www.soinside.com 2019 - 2024. All rights reserved.