How to align two images in two columns in a row?

To make it simple to my real problem, I created two images and used two columns in a row to display. Here is my code:

from dash import Dash, html, dcc, dash_table
import plotly.express as px
import pandas as pd
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
import plotly.graph_objects as go
import skimage.io as skio
external_stylesheets = [dbc.themes.BOOTSTRAP]
app = Dash(__name__, external_stylesheets=external_stylesheets)

def create_image_figure(filename):
   ron = skio.imread(filename)
   figure = px.imshow(ron)
   figure.update_layout(
         xaxis={
            'showgrid': False, 
            'zeroline': False, 
            'visible': False,  
         },
         yaxis={
            'showgrid': False,
            'zeroline': False,
            'visible': False,
         }
       )
   return figure

app.layout = html.Div([
         dbc.Row([dbc.Col(dcc.Graph(id='airplane-image',figure=create_image_figure("airplane.png")),width=4),
                  dbc.Col(dcc.Graph(id='halfairplane-image',figure=create_image_figure("halfairplane.png"), style={'display':'inline-block','vertical-align':'top'}),width=4, style={'display':'inline-block','vertical-align':'top'}),
                 ],
                 justify='center', align='start'),
         ])
if __name__ == '__main__':
   app.run_server(port=8060, debug=True)

Here is what I got:

I tried everything I can think of to align these two images on top, but it just would not work.

Here is what I want:

If somebody can give me some suggestion that will be great. Thanks in advance.

I am still trying to find a solution for my problem as this is very crucial to our project. I have tried almost every suggestion that I can find on web but with no luck. Can somebody from plotly team let me know if there is anything else I can try or there may be a problem with image using align=‘start’ and ‘vertical-align’:‘top’ (btw, I tried verticalAlign too)? thank you very much!

I think the problem that you’re bumping into is that the padding you’re seeing above and below the half-airplane image is coming from inside the SVG canvas that is produced by Dash’s Graph component, rather than from the HTML elements in your page, so no amount of CSS tweaking is going to help align how you want them. As far as the page layout is concerned, your plots are in fact aligned, it’s just that the one on the right has white padding above and below.

If you change the height of the right hand side figure, you’ll see what I mean, as this will reduce the available space to distribute above and below the image:

                    dcc.Graph(
                        id="halfairplane-image",
                        figure=create_image_figure("halfairplane.png").update_layout(
                            height=400
                        ),
                        style={"display": "inlineBlock", "verticalAlign": "top"},
                    )

But that feels like more of a workaround rather than a solution, as it will also change the width of the image at the same time.

Is there a specific reason why’re you’re putting the image in a Graph? If not, I’d suggest using a good old <img> element via Dash’s html.Img component. That way, you’ll be able to style the image directly as you’ve been trying to do without having to worry about the padding generated by the plot. This is how I’d try and get image’s rendering in Dash.

The simplest way to do this is adding your images to an assets folder in your base Dash project directory as described here.

Or you can encode the image in base64 and put that inline in the element as described here.

Also note that when you define CSS styles inline in Dash you need to convert eg inline-blockinlineBlock as I did above.

1 Like

Hi Nedned:

Thank you so much for your response

As matter of fact, my first try was using html.Img. The reason I switched to Graph was because with my project, the ultimate goal is to stream the image, the image data will come from a database and image will grow line by line. (The image can be saved in a numpy.ndarray as shown in my sample code.) to use the html.Img I found the image has to be in the assets folder. Since the image is growing I will need constantly save the image to the assets folder, I also noticed that whenever a new file is created or file is changed under assets folder, the app will be restarted. this is not acceptable. I got the streaming image to work but it grows from middle to top and bottom. the project requirement is grow from top to bottom. That is why I want it to align on top at the beginning. Hope it makes sense to you.

I played more with graph and tried to set the height of the image. I noticed the same thing as you explained at the beginning of your response.

Now I will try to encode the image in base64 as you suggested. In this way at least I don’t need to put the image in the assets folder so that the app will not be restarted whenever a file is saved. The drawback is that I have to save the image every time when new line data comes.

Thank you very much for reminding me using inlineBlock instead of inline-block. I am wondering why there are so many sample code using inline-block and vertical-align. It is very confusing.

I really appreciate your help. I know it probably took a lot of you time to look into it. It is very time consuming. I have spent 3 days on this issue so far.

I will let you know how it goes with the base64 encoding.

Thanks!

1 Like

Hi Nedned:

I forgot to ask if there is a way to use html.Img but use RGB or RGBA numpy.ndarray as input data to display the image?

Thanks

Hi Nedned:

By using the base64 string I was able to display the image align on top. That was good. Further more, from your response and my own research, I am pretty sure that I should not be using dcc.Graph, I should be using html.Img. then I found this website: Black b64-encoded image from numpy array, I was able to reuse the numpy_to_b64(array) function to convert rgb numpy.ndarray to b64 and use html.Img(src=‘data:image/png;base64,{}’.format(img_b64)) to display the image. by using the verticalAlign=‘top’. it works perfectly.

Again, thank you very much for your help. I would not be able to figure this out without your help.

Thanks
Xiali

2 Likes