Plotly 图形组件不能接受视口单位来设置文本注释字体大小

Posted

技术标签:

【中文标题】Plotly 图形组件不能接受视口单位来设置文本注释字体大小【英文标题】:Plotly graph component cannot accept viewport units to set text annotation font size 【发布时间】:2019-05-25 21:10:59 【问题描述】:

我正在使用 Plotly-Dash 并且需要我的文本注释的字体大小与视口宽度一起缩放,就像我的图表一样。对于我布局中的各种标题,我可以直接设置font-size: '1vw',但是vw 不是为style 组件的style 属性设置font-size 的可接受单位。这是相关的回溯:

值错误: 为 scatter.textfont 的“大小”属性接收到无效元素 无效元素包括:['1vw', '1vw', '1vw', '1vw', '1vw', '1vw', '1vw', '1vw', '1vw', '1vw']

The 'size' property is a number and may be specified as:
  - An int or float in the interval [1, inf]
  - A tuple, list, or one-dimensional numpy array of the above

我认为如果dcc.Graph 组件可以接受视口单位(例如style = height: 30vw, width: 30vw)并简单地将它们转换为浏览器端的像素,那么我应该能够使用font-size 执行类似的转换。

在 Python 端是否有一种方法可以检索视口宽度(以像素为单位),以便我可以针对字体大小执行自己的缩放逻辑?

以下是演示此行为的示例 Dash 应用程序:

import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go

labels = 'Point 1': (3.5,5), 'Point 2': (1.5,2), 'Point 3': (3.5,8)

app = dash.Dash(__name__)

app.layout = html.Div([

    html.H1('Test', id='test', style='margin': 50),

    dcc.Graph(id='my-plot', style='margin': 10),

])

@app.callback(
    Output('my-plot', 'figure'),
    [Input('test', 'children')])
def update_graph(val):

    return 

        'data': [go.Scatter(
            x=[v[0]],
            y=[v[1]],
            text=k,
            mode='text'
        ) for k, v in labels.items()],

        'layout': go.Layout(
            margin='l': 40, 'b': 40, 't': 40, 'r': 40,
            shapes=[
                
                    'type': 'path',
                    'path': ' M 1 1 L 1 3 L 4 1 Z',
                    'fillcolor': 'rgba(44, 160, 101, 0.5)',
                    'line': 
                        'color': 'rgb(44, 160, 101)',
                    
                ,
                
                    'type': 'path',
                    'path': ' M 3,7 L2,8 L2,9 L3,10, L4,10 L5,9 L5,8 L4,7 Z',
                    'fillcolor': 'rgba(255, 140, 184, 0.5)',
                    'line': 
                        'color': 'rgb(255, 140, 184)',
                    
                ,
            ]
        )
    

if __name__ == '__main__':
    app.run_server()

【问题讨论】:

能否提供带有文本注释的示例运行代码? 如果此时此问题仍然是相对的,您可以使用 javascript 来解决。只需使用观察者在px 中检查浏览器的视口width,将px 的值放在let 中,然后将其应用于font-sizedcc.Graph 感谢您迄今为止的回复,我已经添加了一个示例 Dash 应用程序,应该作为一个工作示例。 【参考方案1】:

据我了解,仅使用plotly-dash 是无法做到这一点的。 您需要实现的基本上是“响应式”排版,这个主题有一些非常有趣的文章:

https://css-tricks.com/books/volume-i/scale-typography-screen-size/ https://css-tricks.com/snippets/css/fluid-typography/ 字体大小使用em 单位:https://developer.mozilla.org/en-US/docs/Web/CSS/font-size#Ems

Dash 提供了一个应用程序的option to override the default CSS and JS,您可以从layout documentation 看到,如何使用甚至是外部 CSS 文件。

我的建议: 研​​究结果页面,找出文本注释是如何被标记的(id 和/或class),并使用上述文章中提供的方法来创建令人满意的结果. (很抱歉,除了建议,我真的无能为力,但我还没有看到你的代码示例:/)


编辑(评论和问题编辑后):

因此,由于文本注释具有 textpoint 类,我们将使用 override the default CSS:

    创建建议的文件夹结构:

    - app.py
    - assets/
    |--- typography.css
    

    typography.css 上应用上述方法之一(我将通过第二个项目符号示例):

    .textpoint
        font-size: calc(14px + (26 - 14) * ((100vw - 300px) / (1600 - 300)));
    
    

编辑 #2:

我发现了问题和解决方法:

在 Dash 版本 >= 0.22 上添加自定义 CSS 的方法确实是上面的,并且有效。 为了将自定义规则应用于注释,我们需要定位的元素是.textpoint 类中的text 标记(CSS 语法:.textpoint text) 由于某种原因,自定义 CSS 规则被覆盖(可能出于类似原因,在此 SO 帖子的顶部答案中进行了解释:custom css being overridden by bootstrap css)。所以我们需要!important的“核”选项。

利用上述内容,typography.css 应如下所示:

.textpoint text
  font-size: calc(14px + (26 - 14) * ((100vw - 300px) / (1600 - 300))) !important;

【讨论】:

我在我的帖子中添加了一个示例 Dash 应用程序。感谢您迄今为止的周到回复。似乎文本注释被标记为 w/ class="textpoint" @rahlf23 感谢您的更新,我已相应地编辑了我的答案。 由于某种原因,这似乎对我不起作用。在您上面的回答中,typography.css 文件的完整内容正确吗? 您是否能够在您的终端上生成一个有效的 Dash 应用程序,其中文本注释实际上会根据视口宽度调整大小?不幸的是,他们不在我这边。 @rahlf23 您应该删除应用程序初始化的external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']external_stylesheets=external_stylesheets 部分,因为该外部CSS 上的说明可能会覆盖自定义的说明?【参考方案2】:

错误消息说您应该将大小作为int 对象提及。 如果您不能在代码中直接使用 vw,请尝试使用 PySide / PyQt 获取它,然后将其转换为 int 并将其保存在另一个变量 widthheight 下,您可以插入该变量而不是 @ 987654325@.

from PySide import QtGui
#replace that with "from PyQt4 import QtGui" if you're using PyQt4

app = QtGui.QApplication([])
screen_resolution = app.desktop().screenGeometry()
width = int(screen_resolution.width())
height = int(screen_resolution.height())

我不知道您使用的是什么代码,所以我没有尝试过。让我知道它是否适合你。

【讨论】:

很遗憾,我感兴趣的是视口大小而不是屏幕分辨率尺寸,但感谢您的回答。

以上是关于Plotly 图形组件不能接受视口单位来设置文本注释字体大小的主要内容,如果未能解决你的问题,请参考以下文章

如何在具有视口单位的 div 中居中文本?

Dash Plotly Graph(Dash 核心组件抛出错误)

python数据可视化(matplotlib,seaborn,plotly)

Plotly:如何设置绘图图形的样式,使其不显示缺失日期的间隙?

Plotly:如何为使用多条轨迹创建的图形设置调色板?

在 Plotly 的 density_mapbox 可视化中更新底图,同时保留视口