【问题标题】:How to hide index level in pandas <1.4如何在 pandas <1.4 中隐藏索引级别
【发布时间】:2022-11-12 14:43:06
【问题描述】:

我正在尝试使用 pandas 1.3.5 隐藏 pandas Styler 的索引级别。IE。在 pandas 1.4 中复制 hide(axis="index", level="level_name") 的行为。

这是我正在尝试的一个最小示例:

def multi_highlighter(row, range_colors):
    def find_color(value):
        for color, threshold in range_colors.items():
            if value < threshold:
                return color
        return "white"

    return [f"background-color: {find_color(v)}" for v in row]

range_colors = {"red": 18, "orange": 100}

data = pd.DataFrame({
    "Ex Date": ['2022-06-20', '2022-06-20', '2022-06-20', '2022-06-20', '2022-06-20', '2022-06-20', '2022-07-30', '2022-07-30', '2022-07-30'], 
    "Portfolio": ['UUU-SSS', 'UUU-SSS', 'UUU-SSS', 'RRR-DDD', 'RRR-DDD', 'RRR-DDD', 'KKK-VVV', 'KKK-VVV', 'KKK-VVV'],
    "Position": [120, 90, 110, 113, 111, 92, 104, 110, 110],
    "Strike": [18, 18, 19, 19, 20, 20, 15, 18, 19],
    })
(
    data
    .reset_index()
    .set_index(["Ex Date", "Portfolio", "index"])
    .style
    .apply(multi_highlighter, range_colors=range_colors, axis=1)
)

添加一些边框,它会生成下表:

现在要隐藏“索引”索引级别,我尝试通过从 answer 添加 CSS 样式来实现这一点,如下所示:

.set_table_styles([{'selector': 'tr th:nth-child(3), tr td:nth-child(3)', 'props': [
    ('display', 'None')]}], overwrite=False)

但它给了我这个结果:

【问题讨论】:

    标签: html css python-3.x pandas pandas-styles


    【解决方案1】:

    pandas 1.3.5 中有一些选项,尽管在不使用 1.4.0 中可用的 hide 函数的情况下,这是一个不平凡的操作。

    删除索引级别 >= 1

    由于在 MultiIndex 中使用了行跨度,nth-child 无法在此处工作。但是,我们可以利用 Styler (style.py L158-L171) 添加的默认 CSS 类:

    • 索引和列名包括index_namelevel&lt;k&gt; 其中k 是它在MultiIndex 中的级别

    • 索引标签单元格包括

      • row_heading
      • row&lt;n&gt; 其中n 是行的数字位置
      • level&lt;k&gt; 其中k 是MultiIndex 中的级别
    • 列标签单元格包括

      • col_heading
      • col&lt;n&gt; 其中n 是列的数字位置
      • level&lt;k&gt; 其中k 是 MultiIndex 中的级别
    • 空白单元格包括blank

    所以我们可以简单地排除 CSS 选择器.level2:not(.col_heading),其中n 是我们想要隐藏的任何级别(级别0 需要稍作修改)。我们需要排除 col_heading 以便我们不删除任何列标题。

    此外,然后我们需要删除其中一个blank 级别,以便顶级对齐。我采取了简单的方法,并选择删除每一行的第一个空白。

    注意:这不是一个持久的解决方案,并且会受到 MultiIndex 列等结构更改的影响。

    这是一个使用样式隐藏级别 2 的示例

    hide_column_styles = [
        {
            # Remove all row values associated with level2
            'selector': f'th.level2:not(.col_heading)',
            'props': [('display', 'none')]
        },
        {
            # Remove the first th in each row if it is .blank
            'selector': 'thead th:first-child.blank',
            'props': [('display', 'none')]
        }
    ]
    
    # Basic border
    border_styles = [{
        'selector': '',
        'props': [('border-collapse', 'collapse')]
    }, {
        'selector': 'table, th, td',
        'props': [('border', '1px solid black')]
    }]
    (
        data.reset_index()
            .set_index(["Ex Date", "Portfolio", "index"])
            .style
            .apply(multi_highlighter, range_colors=range_colors, axis=1)
            .set_table_styles([*hide_column_styles, *border_styles])
    )
    


    删除索引级别 0

    如果试图移除 level0,我们只需要隐藏 level0:

    hide_column_styles = [
        {
            # Remove all values associated with level0 (including the first header row)
            'selector': f'th.level0:not(.col_heading)',
            'props': [('display', 'none')]
        }
    ]
    

    第一个索引列将具有类 .level0 并被隐藏而不需要额外的选择器:

    <tr>
      <th class="blank">&nbsp;</th>
      <th class="blank">&nbsp;</th>
      <th class="blank level0">&nbsp;</th> <!-- This will match and be hidden -->
      <th class="col_heading level0 col0">Position</th>
      <th class="col_heading level0 col1">Strike</th>
    </tr>
    

    隐藏不影响 MultiIndex 唯一性的级别

    如果删除级别后索引级别保持唯一,则可以仅通过 droplevel 删除索引创建样式器:

    例如,这是一个通过删除级别 0 来删除它的示例。

    n = 0  # level to drop
    (
        data
            .reset_index()
            .set_index(["Ex Date", "Portfolio", "index"])
            .droplevel(level=n)  # Drop level from DataFrame
            .style
            .apply(multi_highlighter, range_colors=range_colors, axis=1)
            .set_table_styles([
            {
                'selector': 'table, th, td',
                'props': [('border', '1px solid black')]
            }
        ])
    )
    

    注意:这仅在 MultiIndex 是唯一的情况下才有效该级别已删除

    如果一个级别下降导致非唯一的 MultiIndex(如级别 2),则在使用 Styler.applyStyler.applymap 时将发生 KeyError:

    KeyError: 'Styler.apply.applymap 与非唯一索引或列不兼容。'


    熊猫 1.4.0 及更新版本

    只是为了让这个问题的任何未来读者都非常清楚,这是 1.4.0 之前版本的解决方法。这是很多使用 hide 函数更简单,并且该解决方案比 CSS 选择器更耐用:

    n = 2  # level to drop
    border_styles = [{
        'selector': '',
        'props': [('border-collapse', 'collapse')]
    }, {
        'selector': 'table, th, td',
        'props': [('border', '1px solid black')]
    }]
    
    (
        data
            .reset_index()
            .set_index(["Ex Date", "Portfolio", "index"])
            .style
            .apply(multi_highlighter, range_colors=range_colors, axis=1)
            .hide(axis=0, level=n)
            .set_table_styles(border_styles)
    )
    

    【讨论】:

      【解决方案2】:

      为了完全删除索引列而不是使用 CSS 样式隐藏它,我使用了 BeautifulSoup:

      def drop_idex_level(html_body: str, level: int):
          soup = BeautifulSoup(html_body, 'html.parser')
          css_selector = f"th.level{level}:not(.col_heading), thead th:first-child.blank"
          for e in soup.select(css_selector):
              e.decompose()
          return soup.prettify( formatter="html")
      

      此函数需要一个 html 正文和要删除的索引级别,使用 @Henry 答案中的选择器选择元素并将它们从正文中删除。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-03
        • 2023-03-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-01
        • 1970-01-01
        相关资源
        最近更新 更多