Hi all,
this is my first post and I have to say I already love Streamlit
My question is: can I display an image in a table created with the component AgGrid?
Thanks,
Vins
Hi all,
this is my first post and I have to say I already love Streamlit
My question is: can I display an image in a table created with the component AgGrid?
Thanks,
Vins
I came looking for this feature. Currently displaying a peek of file paths, would be handy to display the related images as a thumbnail
Hi @Tobias_Schiele , @Vincenzo_Cacciatore , @Shinigami86 has already managed to do this. Check out this link: Ag-Grid component with input support - #63 by PablocFonseca
Cheers
Wow, thank you so much for your fast reply. That’s definitely something to work with. At the moment I am not able to use a JS solution as my image assets can exist outside of the streamlit host directory, thus they have to be loaded on the server-side. But hey, it’s a start! Maybe I can load each image, create a thumbnail on the fly and directly communicate the images to AgGrid. Thank you!
Hi,
I tried to adapt the code to display images in Ag-grid Table cell but It’s not working.
import pandas as pd
from st_aggrid import AgGrid, GridUpdateMode, DataReturnMode, JsCode
from st_aggrid.grid_options_builder import GridOptionsBuilder
df = pd.DataFrame({"Name": ["Elon", "Bill"],
"Image":[{'src':"https://fr.wikipedia.org/wiki/Elon_Musk#/media/Fichier:Elon_Musk_Royal_Society.jpg", 'alt':'Elon'},
{'src':"https://fr.wikipedia.org/wiki/Bill_Gates#/media/Fichier:Bill_Gates_-_Nov._8,_2019.jpg", 'alt':'Bill'},
],
})
options_builder = GridOptionsBuilder.from_dataframe(df)
image_render = JsCode("""function (params) {
this.params = params;
this.img_render = document.createElement('div');
this.img_render.innerHTML = `
<img src=${this.params.src}
alt=${this.params.alt}
width="50"
height="50"
>
`;
return this.img_render;
}""")
options_builder.configure_column("Image",
headerName="Image",
cellRenderer=image_render)
grid_options = options_builder.build()
grid_return = AgGrid(df,
grid_options,
theme="streamlit",
allow_unsafe_jscode=True,
)
Any suggestions?
Hi @Marc_Richard, this has already been done. Check out this link: Ag-Grid component with input support - #63 by PablocFonseca
Cheers
Hi Shawn,
yes, I already tried this explore this example but I didn’t find how to code the right dataframe since in the post, he only shared the JScode and not the rest of the code. I am not sure why this is params.data.NATION_PATH and params.value because there is no example of the data column construction.
Any ideas?
thank you.
UPDATE:
my image url was not correct! It works now by using the example of PablocFonseca and the right image url.
import pandas as pd
from st_aggrid import AgGrid, GridUpdateMode, DataReturnMode, JsCode
from st_aggrid.grid_options_builder import GridOptionsBuilder
df = pd.DataFrame({"image_path":["https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Elon_Musk_Royal_Society.jpg/800px-Elon_Musk_Royal_Society.jpg",
"https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Bill_Gates_-_Nov._8%2C_2019.jpg/390px-Bill_Gates_-_Nov._8%2C_2019.jpg"],
"Name":['Elon', 'Bill']
})
options_builder = GridOptionsBuilder.from_dataframe(df)
image_nation = JsCode("""function (params) {
console.log(params);
var element = document.createElement("span");
var imageElement = document.createElement("img");
imageElement.src = params.data.image_path;
imageElement.width="40";
imageElement.height="40";
element.appendChild(imageElement);
element.appendChild(document.createTextNode(params.value));
return element;
}""")
options_builder.configure_column('Name', cellRenderer=image_nation)
grid_options = options_builder.build()
grid_return = AgGrid(df,
grid_options,
theme="streamlit",
allow_unsafe_jscode=True,
)
Code Explanation: I have created a dataframe with 4 columns - this is fairly self-explanatory.
The 1st 2 images are stored locally on my hard drive in the mentioned path (which you can change if you plan to use local images). These need to be base64 and the function ‘ReadPictureFile’ does that conversion. For all local images, I iterrows of the dataframe and add the preliminary text ‘data:image/…’ - ref code
The last 2 images are directly accessed from the web and does not need any change in the image path column.
I hide the image path column, as this is not needed to be displayed.
I show the picture in the Face column.
Before trying the following code, you need to copy 2 images to your local folder and change the path and filenames of the 1st 2 images in the code. The code is below:
import streamlit as st
import pandas as pd
from st_aggrid import GridOptionsBuilder, AgGrid
from st_aggrid.shared import JsCode
import base64
def ReadPictureFile(wch_fl):
try:
return base64.b64encode(open(wch_fl, 'rb').read()).decode()
except:
return ""
ShowImage = JsCode("""function (params) {
var element = document.createElement("span");
var imageElement = document.createElement("img");
if (params.data.ImgPath != '') {
imageElement.src = params.data.ImgPath;
imageElement.width="20";
} else { imageElement.src = ""; }
element.appendChild(imageElement);
element.appendChild(document.createTextNode(params.value));
return element;
}""")
df = pd.DataFrame({'Name': ['Iron Man', 'Walter White', 'Wonder Woman', 'Bat Woman'],
'Face': ['', '', '', ''],
'ImgLocation': ['Local', 'Local', 'Web', 'Web'],
'ImgPath': ['D:/ShawnP/icon-im.png',
'D:/ShawnP/icon-ww.png',
'https://i.pinimg.com/originals/ab/26/c3/ab26c351e435242658c3783710e78163.jpg',
'https://img00.deviantart.net/85f5/i/2012/039/a/3/batwoman_headshot_4_by_ricber-d4p1y86.jpg'] })
if df.shape[0] > 0:
for i, row in df.iterrows():
if row.ImgLocation == 'Local':
imgExtn = row.ImgPath[-4:]
row.ImgPath = f'data:image/{imgExtn};base64,' + ReadPictureFile(row.ImgPath)
gb = GridOptionsBuilder.from_dataframe(df)
gb.configure_column('Face', cellRenderer=ShowImage)
gb.configure_column("ImgPath", hide = "True")
vgo = gb.build()
AgGrid(df, gridOptions=vgo, theme='blue', height=150, allow_unsafe_jscode=True )
Hope the above is understandable.
Cheers
This solution no longer seems to work, nor does the one described here: Enhancing AgGrid table with Image Display in Streamlit Apps | by Avra | The Streamlit Teacher | Medium.
I’m getting an error in the streamlit app page " Component Error: Minified React error #31; visit https://reactjs.org/docs/error-decoder.html?invariant=31&args[]=[object%20HTMLImageElement] for the full message or use the non-minified dev environment for full errors and additional helpful warnings."
Does anybody know how to resolve this?
I figured it out myself. Here is what I did:
thumbnail_renderer = JsCode(“”"
class ThumbnailRenderer {
init(params) {
this.eGui = document.createElement(‘img’);
this.eGui.setAttribute(‘src’, params.value);
this.eGui.setAttribute(‘width’, ‘100’);
this.eGui.setAttribute(‘height’, ‘auto’);
}
getGui() {
return this.eGui;
}
}
“”")
gb.configure_column(“Thumbnail”, “Thumbnail”, cellRenderer=thumbnail_renderer)
this worked for me as well, thank you for the solution @o7gyk9wlr :
thumbnail_renderer = JsCode("""
class ThumbnailRenderer {
init(params) {
this.eGui = document.createElement('img');
this.eGui.setAttribute('src', params.value);
this.eGui.setAttribute('width', '100');
this.eGui.setAttribute('height', 'auto');
}
getGui() {
console.log(this.eGui);
return this.eGui;
}
}
""")
gd.configure_column("IMAGE_URL", cellRenderer=thumbnail_renderer)
for some reason this did not >
image_renderer = JsCode(
"""
function renderImage(params) {
var img = document.createElement('img');
img.src = params.value;
img.alt = 'Your Image';
img.width = 50;
img.height = 50;
console.log(img);
return img;
}
"""
)
gd.configure_column('IMAGE_URL', cellRenderer=image_renderer)
I would get the error: Minified React error #31
Minified React error #31 – React.
I asked chat gpt and the answer was:
but why in the new version I am not getting the minified react error 31 Objects are not valid as a React child (found: [object HTMLImageElement]). If you meant to render a collection of children, use an array instead.
ChatGPT:
The reason you’re not getting the minified React error #31 in your version is because you’re not directly returning the HTML element itself from your JavaScript code. Instead, you’re encapsulating the HTML element within a JavaScript class (ThumbnailRenderer
) and returning an instance of that class.
When Ag-Grid renders the cell content, it expects a valid React component or an array of React components. In your class-based implementation, you’re effectively returning a custom class instance (ThumbnailRenderer
) which Ag-Grid handles as a valid React component, allowing it to render without triggering the error.
In contrast, in the previous implementations where you directly returned the HTML element (img
), React attempted to render the HTML element itself, which is not a valid React component and resulted in the error. By encapsulating the HTML element within a custom class and returning an instance of that class, you’re effectively providing a valid React component for Ag-Grid to render, thus avoiding the error.
I expanded the code since I want to pop over the image inside the page when the user clicks it, just like in the st.data_editor, and used ChatGPT again, the code:
class ThumbnailRenderer {
init(params) {
this.eGui = document.createElement('div'); // Create a container div
this.eGui.style.display = 'flex'; // Set display to flex
this.eGui.style.justifyContent = 'center'; // Center horizontally
this.eGui.style.alignItems = 'center'; // Center vertically
const img = document.createElement('img'); // Create img element
img.setAttribute('src', params.value); // Set src attribute
img.setAttribute('width', '100'); // Set width
img.setAttribute('height', 'auto'); // Set height to auto to maintain aspect ratio
img.style.cursor = 'pointer'; // Add pointer cursor to indicate clickable
this.eGui.appendChild(img); // Append img to container div
// Add event listener for click event on the image
img.addEventListener('click', () => {
// Create a modal or popover to display the enlarged image
const modal = document.createElement('div');
modal.style.position = 'fixed';
modal.style.top = '0';
modal.style.left = '0';
modal.style.width = '100%';
modal.style.height = '100%';
modal.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
modal.style.display = 'flex';
modal.style.justifyContent = 'center';
modal.style.alignItems = 'center';
const enlargedImg = document.createElement('img');
enlargedImg.setAttribute('src', params.value);
enlargedImg.style.maxWidth = '90%';
enlargedImg.style.maxHeight = '90%';
modal.appendChild(enlargedImg);
// Close modal when clicking outside the image
modal.addEventListener('click', (event) => {
if (event.target === modal) {
modal.remove();
}
});
document.body.appendChild(modal);
});
}
getGui() {
return this.eGui;
}
}
The result
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.