Hi Streamlit team!  First, thank you very much for creating Streamlit.  I can’t begin to express how much this helps with my day-to-day challenges.  I have completely moved off of my custom Flask/React tool that I created to manage my workflow.
My current area of focus is OCR from highly quantized images.  My models require copious amount of tuning and adjustments along with combinations of multiple feature extractors to work.  To this end, when I’m processing my image or video sources, I need to be able to see how all the feature extractions work side-by-side.  My solution within Streamlit was to create a Dataframe with embedded PIL Images, that I use a custom formatter on.  I got the idea from here:
https://www.kaggle.com/stassl/displaying-inline-images-in-pandas-dataframe 41
I would prefer to be able to simply use the Pandas Styler, but unfortunately their format does not allow the embedding of HTML currently, though it is mentioned as a possible future enhancement.
The other way I could work around this is by creating a custom Jinja2 template the Styler uses and repurpose the current Pandas html.tpl, see here:

  
      github.com
  
  
    pandas-dev/pandas/blob/4e5c9d413ab58033529899de990bf6b25bcdeb22/pandas/io/formats/templates/html.tpl 42
{# Update the template_structure.html document too #}
{%- block before_style -%}{%- endblock before_style -%}
{% block style %}
<style  type="text/css" >
{% block table_styles %}
{% for s in table_styles %}
    #T_{{uuid}} {{s.selector}} {
    {% for p,val in s.props %}
      {{p}}: {{val}};
    {% endfor -%}
    }
{%- endfor -%}
{% endblock table_styles %}
{% block before_cellstyle %}{% endblock before_cellstyle %}
{% block cellstyle %}
{%- for s in cellstyle %}
    #T_{{uuid}}{{s.selector}} {
    {% for p,val in s.props %}
        {{p}}: {{val}};
    {% endfor %}


  This file has been truncated. show original

  
  
    
    
  
  


This would in my opinion be a complete abuse of the Styler as I would have to override the displaying of the table elements in the TR block, with the undocumented r & c values which could easily be renamed in the future.
Here is a sample of the code I use to display images within a Pandas table:
def get_thumbnail(path):
  i = Image.open(path)
  i.thumbnail((150, 150), Image.LANCZOS)
  return i

def image_base64(im):
  base64Image = None
  if isinstance(im, str):
    im = get_thumbnail(im)
  with BytesIO() as buffer:
    im.save(buffer, 'jpeg')
    base64Image = base64.b64encode(buffer.getvalue()).decode()
  return base64Image

def image_formatter(im):
  return f'<img src="data:image/jpeg;base64,{image_base64(im)}">'

def run_the_app():
...
  df = pd.DataFrame(data)
  st.markdown(df.to_html(formatters={'image': image_formatter}, escape=False), unsafe_allow_html=True)
...

As you can see I perform a to_html() on the DataFrame with a custom formatter, and then pass the result to st.markdown.  While this solution meets my needs it is not ideal, as I cannot leverage the Pandas Styler as its render method will not allow disabling of escaping HTML tags.
I hope this helps better understand my personal need of HTML.  If I may make a recommendation, remove html from markdown and make st.html() a first-class citizen. Or make PIL Images a valid type in Streamlit dataframes which get rendered in the browser.