【问题标题】:Can I control the inline css created by Bokeh (or remove it completely)?我可以控制 Bokeh 创建的内联 css(或完全删除它)吗?
【发布时间】:2019-06-07 23:33:39
【问题描述】:

我正在 PyViz 面板中创建一个仪表板,据我了解,它在后台使用散景。它易于使用,我很快就得到了 90% 的解决方案,但最终的布局(对我来说)更容易使用普通的旧 CSS(网格布局或其他东西)。我可以将 html id 和类附加到 Python 中的每个小部件/绘图/列/行等,但我还没有找到一种方法来阻止散景在它产生的每个 div 上包含一长串内联 css。我希望布局是响应式的,没有硬编码的宽度/高度或类似的东西。

我已经在template/index.html 的目录中提供来自main.ipynb 的面板代码,因此涉及模板的解决方案完全可以。如果不需要,我不想在添加到模板的许多不同根目录中创建整个仪表板,如果我可以删除生成的内联 css 属性,则从行和列生成的 html 非常适合我的目的.

我可以编写一个 Python 函数来遍历面板/散景小部件树并在需要时修改小部件。我当然也可以在 Javascript 中遍历 DOM,并在创建 div 时从 div 中删除样式属性,但这似乎不如将一些 !important css 组合在一起那么优雅。

旁白:有谁知道如何阻止散景从 Javascript 更改 html 标题属性,或者如何从面板设置标题?

仪表板示例:

这是一个没有任何自定义样式的简约仪表板。它在每个 div 上生成硬编码的宽度和高度(从 Firefox devtools 元素检查器中可以看出)。仪表板左对齐并且没有有效地使用屏幕空间(左侧有很多空白,直方图的水平宽度与上面的行不同)。调整页面大小时,布局也没有响应。

import numpy
import pandas
import param
import panel
import holoviews
from IPython.display import display


panel.extension()
holoviews.extension('bokeh')

# Create syntetic dataset
N= 1000
age = numpy.random.gamma(10, 1.5, N)
defects = numpy.clip(numpy.random.chisquare(5, N) * age - 10, 0, 1e100).astype(int)
df = pandas.DataFrame({'age': age, 'defects': defects})
display(df.head(3))

# default sizing_mode
SM = 'stretch_width'


class DashboardDefinition(param.Parameterized):
    age = param.Range((0, 20), (0, None), softbounds=(0, 30))
    histogram = param.ObjectSelector('defects', ['defects', 'age'])

    def filter_data(self, table):
        return table.select(age=self.age)

    @param.depends('age')
    def make_scatter(self):
        scatter = holoviews.Points(df, ['age', 'defects'])
        selected = self.filter_data(scatter)
        return panel.panel(selected, sizing_mode=SM)

    @param.depends('age', 'histogram')
    def make_histogram(self):
        table = holoviews.Table(df, self.histogram)
        table = self.filter_data(table)
        frequencies, edges = numpy.histogram(table[self.histogram], 15)
        hist = holoviews.Histogram((frequencies, edges))
        return panel.panel(hist, sizing_mode=SM)

    def layout(self):
        return panel.Column(panel.Row(self.param,
                                      self.make_scatter,
                                      sizing_mode=SM),
                            self.make_histogram,
                            sizing_mode=SM)


dashboard = DashboardDefinition(name='Dashboard parameters')
dash_panel = dashboard.layout() 

# Define the dashboard
template = """
{% extends base %}

{% block title %}Hello world{% endblock %}

{% block contents %}
<h1>My dashboard</h1>
<p>This is my currently unstyled dashboard</p>
<br>
{{ embed(roots.dash1) }}
{% endblock %}
"""
tmpl = panel.Template(template)
tmpl.add_panel('dash1', dash_panel)
tmpl.servable()

# Uncomment to preview dashboard in jupyter notebook
#dash_panel

【问题讨论】:

    标签: python css bokeh pyviz


    【解决方案1】:

    我通过在 holoviews 中设置 responsive=True 解决了我的具体问题(感谢 https://gitter.im/pyviz/pyviz 中的 xavArtley 帮助我完成这部分)。从散景文档看来,此选项已被删除,但它存在于 holoviews 中,使用它可以使内联 css 与我想要的匹配。

    必须在 javascript 运行之前为元素设置样式,否则大小会出错,但是您可以通过将自定义 css 放入模板序言中来做很多事情(后序将不起作用,至少不会在 Firefox 中)。

    一个工作示例

    这里仪表板周围的容器决定仪表板组件的大小,而不是内联 css(由 Javascript 设置以匹配周围的 div 元素):

    import numpy
    import pandas
    import param
    import panel
    import holoviews
    
    
    panel.extension()
    holoviews.extension('bokeh')
    
    # Create syntetic dataset
    N= 1000
    age = numpy.random.gamma(10, 1.5, N)
    defects = numpy.clip(numpy.random.chisquare(5, N) * age - 10, 0, 1e100).astype(int)
    df = pandas.DataFrame({'age': age, 'defects': defects})
    
    
    class DashboardDefinition(param.Parameterized):
        age = param.Range((0, 20), (0, None), softbounds=(0, 30))
        histogram = param.ObjectSelector('defects', ['defects', 'age'])
    
        def filter_data(self, table):
            return table.select(age=self.age)
    
        @param.depends('age')
        def make_scatter(self):
            scatter = holoviews.Points(df, ['age', 'defects'])
            selected = self.filter_data(scatter)
            hv_obj = selected.options(responsive=True, aspect=3)
            return panel.panel(hv_obj)
    
        @param.depends('age', 'histogram')
        def make_histogram(self):
            table = holoviews.Table(df, self.histogram)
            table = self.filter_data(table)
            frequencies, edges = numpy.histogram(table[self.histogram], 25)
            hist = holoviews.Histogram((frequencies, edges))
            hv_obj = hist.options(responsive=True, aspect=4)
            return panel.panel(hv_obj)
    
        def layout(self):
            return panel.Column(panel.Row(self.param,
                                          self.make_scatter,
                                          sizing_mode='stretch_width'),
                                self.make_histogram,
                                sizing_mode='stretch_width')
    
    
    dashboard = DashboardDefinition(name='Dashboard parameters')
    dash_panel = dashboard.layout() 
    
    # Define the dashboard
    template = """
    {% extends base %}
    
    {% block preamble %}
    <style>
    div#dashboard {
        width: 80%;
        margin: 0 auto;
    }
    </style>
    {% endblock preamble %}
    
    {% block contents %}
    <div id="dashboard">
      <h1>My dashboard</h1>
      {{ embed(roots.dash1) }}
    </div>
    {% endblock contents %}
    """
    tmpl = panel.Template(template)
    tmpl.add_panel('dash1', dash_panel)
    tmpl.servable(title="My page title")
    
    # Uncomment to preview dashboard in jupyter notebook
    #dash_panel
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-18
      • 2012-04-06
      • 2023-01-25
      • 2020-01-07
      • 2022-11-27
      • 2020-01-31
      相关资源
      最近更新 更多