skip to Main Content

I’m working on generating an HTML table dynamically in Python based on a pandas DataFrame. The table includes both for headers and for rows of data. However, I’m running into an issue where my rows () are not properly contained within a single tag.

Here is the function I currently have:

def Analyse(df_multiselect):
    # Define the table structure with thead and tbody in one place
    table_html = """
    <table id="data-table" class="table display nowrap" width="auto">
        <thead>
            <tr>
                <th colspan="1">المواد</th>
                <th colspan="1">الحاضرون</th>
                <th colspan="1">المتوسط الحسابي</th>
                <th colspan="1">الانحراف المعياري</th>
                <th colspan="1">التباين</th>
                <th colspan="1">أعلى نقطة</th>
                <th colspan="1">الوسيط</th>
                <th colspan="1">أدنى نقطة</th>
                <th colspan="1">المدى</th>
            </tr>
        </thead>
        <tbody>
    """
    
    # Dynamically select subjects and columns
    subjects = df_multiselect.columns[11:26]  # Modify to match your actual column indices
    columns = df_multiselect.iloc[:, 11:26]

    # Calculate the statistics
    counts = columns.count()
    means = round(columns.mean(), 2)
    stdvs = round(columns.std(), 2)
    maxs = columns.max()
    mins = columns.min()
    ranges = round(maxs - mins, 2)
    variances = round(columns.var(), 2)
    medians = round(columns.median(), 2)

    # Loop through each subject to build the table rows
    for i, subject in enumerate(subjects):
        row = f"""
        <tr>
            <td>{subject}</td>
            <td>{counts.iloc[i]}</td>
            <td>{means.iloc[i]:.2f}</td>
            <td>{stdvs.iloc[i]:.2f}</td>
            <td>{variances.iloc[i]:.2f}</td>
            <td>{mins.iloc[i]}</td>
            <td>{medians.iloc[i]}</td>
            <td>{maxs.iloc[i]}</td>
            <td>{ranges.iloc[i]}</td>
        </tr>
        """
        table_html += row  # Add the current row to the table HTML

    # Close the tbody tag and the table
    table_html += "</tbody></table>"

    return table_html


# Generate the table HTML by calling Analyse
table_html = Analyse(df_multiselect)

# Generate the full HTML page to display
full_html = f"""
    <section>
        <div class="container">
            <div class="row g-5 align-items-center">
                <a id="titleElement" class="btn btn-primary-soft">تحليل النتائج
                </a>
                <div class="about-image-gallery">
                    <div class="scroll-container">    
                        {table_html}
                    </div> 
                </div>
            </div>
        </div>
    </section>
"""

# Display the HTML content in Streamlit using st.markdown
st.markdown(full_html, unsafe_allow_html=True)  

Problem:
This function seems to generate only one inside the tag, while the other rows are placed outside the in the resulting HTML. I need all rows to be properly encapsulated inside a single tag.

What I’ve Tried:
I checked the loop logic and ensured all rows are being added inside the loop.
Verified the final table_html structure by printing it, and the issue persists.

Desired Output:
A valid HTML table where all rows are correctly contained within one tag.

Example Expected Table:

<table>
    <thead>
        <tr>
            <th>Subject</th>
            <th>Count</th>
            <th>Mean</th>
            <th>Std Dev</th>
            <th>Variance</th>
            <th>Max</th>
            <th>Median</th>
            <th>Min</th>
            <th>Range</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Math</td>
            <td>30</td>
            <td>14.56</td>
            <td>2.34</td>
            <td>5.48</td>
            <td>20</td>
            <td>15</td>
            <td>10</td>
            <td>10</td>
        </tr>
        <tr>
            <td>Science</td>
            <td>28</td>
            <td>13.42</td>
            <td>2.12</td>
            <td>4.98</td>
            <td>19</td>
            <td>14</td>
            <td>11</td>
            <td>8</td>
        </tr>
        <!-- Additional rows -->
    </tbody>
</table>

2

Answers


  1. Chosen as BEST ANSWER

    problem resolved: The suggestion to remove trailing newlines in my row construction is a good one so i have Updated my loop to avoid extra whitespace.

    # Loop through each subject to build the table rows
        for i, subject in enumerate(subjects):
            row = (
            f"<tr>"
                f"<td>{subject}</td>"
                f"<td>{counts.iloc[i]}</td>"
                f"<td>{means.iloc[i]:.2f}</td>"
                f"<td>{stdvs.iloc[i]:.2f}</td>"
                f"<td>{variances.iloc[i]:.2f}</td>"
                f"<td>{mins.iloc[i]}</td>"
                f"<td>{medians.iloc[i]}</td>"
                f"<td>{maxs.iloc[i]}</td>"
                f"<td>{ranges.iloc[i]}</td>"
            f"</tr>"
            )
    

  2. Why going through all that complexity when you can simply use pandas.DataFrame.to_html?! It will write the html from the df for you in 1 line.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search