Search code examples
python-3.xflaskjinja2

How to highlight rows based on a column value that matches a string in Jinja?


I am working with FLASK and Jinja. I have a dataframe named as df:

Name      Marks   Remarks
Joseph      40    Warning
Tom         60    Satisfied

In flask pass the dataframe as follows:

df=[df.to_html(classes='data', justify='center', header="true",index=False)]

In Jinja, I have the following code:

{% for grouped_table in df %}
     {{ grouped_table|safe }}

I would like to highly the background based on the value of "Remarks" column. When the value is "Warning" it should be red, otherwise green.

In the following article, How to highlight rows based on a column value that only appears x amount of times?, it is mentioned that we can use df.style.apply(lambda s: colors) for highlighting a cell based on value.

However, I am not sure how to implement it in Jinja. Is it possible to implement the logic in FLASK and then pass it to Jinja?

Thanks in advance for any valuable suggestions/solutions!


Solution

  • Instead of using to_html it is possible to use the styler to set the properties of the table.
    To set values depending on the background color you can use applymap. This allows the properties to be assigned directly to the respective cells. All other properties can be assigned by normal css rules.

    from flask import (
        Flask, 
        render_template 
    )
    import pandas as pd 
    
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        df = pd.DataFrame(
            [['Joseph', 40, 'Warning'], ['Tom', 60, 'Satisfied']],
            columns=['Name', 'Marks', 'Remarks']
        )
    
        def bg_color_by_value(value):
            clr = 'red' if value == 'Warning' else 'green'
            return f'background-color: {clr}'
    
        table = df.style\
                .applymap(bg_color_by_value, subset=['Remarks'])\
                .hide(axis='index')\
                .set_table_attributes('class="dataframe data"')\
                .to_html()
    
        return render_template('index.html', **locals())
    
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title></title>
        <style>
            table.dataframe {
                table-layout: fixed;
                border-collapse: collapse;
                color: #3f3f3f;
                font-family: Arial;
                width: 100%;
            }
            table.dataframe thead tr th {
                background-color: #777;
                color: #fff;
            }
            table.dataframe td, th 
            {
                padding: 5px;
                border: 1px solid #777;
            }
            table.dataframe tbody tr:nth-child(even)
            {
                background-color: #eee;
            }
            table.dataframe tbody tr td, 
            table.dataframe tbody tr th 
            {
                border: 1px dotted #ccc;
            }
            table.dataframe tbody tr:last-child td, 
            table.dataframe tbody tr:last-child th 
            {
                border-bottom: 0;
            }
            table.dataframe tbody tr:first-child td, 
            table.dataframe tbody tr:first-child th 
            {
                border-top: 0;
            }
        </style>
    </head>
    <body>
        {{ table|safe }}
    </body>
    </html>