Cannot change matplotlib figure size

Hello everyone. My matplotlib figure is too big, and I canā€™t change its size. I tried passing the figsize parameter both when creating the fig object and in the st.pyplot method. The figure size does not change.

Reproduce:

import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(5, 5))
st.pyplot(fig, figsize=(5, 5))
3 Likes

Iā€™d like to know this too, itā€™s frustrating to not have control over this.

Hi @Zylatis, Iā€™m sorry to hear youā€™re having trouble with resizing matplotlib figures. :confused:

Could you share a working example or code a snippet where you are trying unsuccessfully to resize a figure? We could try figuring it out together.

In the meantime, I put together a minimal example based on a matplotlib tutorial. I vary the values of the width and height parameters in figsize using sliders:

import streamlit as st
import matplotlib.pyplot as plt

cat = ["bored", "happy", "bored", "bored", "happy", "bored"]
dog = ["happy", "happy", "happy", "happy", "bored", "bored"]
activity = ["combing", "drinking", "feeding", "napping", "playing", "washing"]

width = st.sidebar.slider("plot width", 1, 25, 3)
height = st.sidebar.slider("plot height", 1, 25, 1)

fig, ax = plt.subplots(figsize=(width, height))
ax.plot(activity, dog, label="dog")
ax.plot(activity, cat, label="cat")
ax.legend()

st.pyplot(fig)

Click on the GIF below to see resizing in action:

Happy Streamlit-ing! :balloon:
Snehan

5 Likes

According to the streamlit docs we can only pass key word arguments for Matplotlibā€™s savefig function to st.pyplot.

However, this table indicates savefig does not have a figsize key word.

Here is a code snippet that demonstrate where resizing works (i.e. tabular data) and where it does not work (i.e. array data)

EDIT: I just discovered st.image, I guess probably should use that for arrays in streamlit. Will leave matplotlib array example belowā€¦

import streamlit as st
import matplotlib.pyplot as plt
import numpy as np

# tabular data

table = {

  'cat':["bored", "happy", "bored", "bored", "happy", "bored"],
  'dog':["happy", "happy", "happy", "happy", "bored", "bored"],
  'activity':["combing", "drinking", "feeding", "napping", "playing", "washing"]

}

# array data

array = np.zeros((100,100))

# visualization algorithms

def display_table(table, figsize=(5,5)):
  "example of displaying a table in streamlit"
  fig, ax = plt.subplots(figsize=figsize)
  ax.plot(table['activity'], table['dog'], label="dog")
  ax.plot(table['activity'], table['cat'], label="cat")
  st.pyplot(fig)

def display_array(array, figsize=(5,5)):
  "example of displaying an array in streamlit"
  fig, ax = plt.subplots(figsize=figsize)
  _ = ax.imshow(array)
  st.pyplot(fig)

# this works
display_table(table, figsize=(10,5))

# this does not work properly
display_array(array, figsize=(2,4))

Here is an example displaying a numpy array using st.image

import streamlit as st
import matplotlib
import numpy as np

def display_array(arr, colormap='viridis', width=None):
  """ display a 2D array in streamlit with a color map"""

  # color map
  cm = matplotlib.cm.get_cmap(colormap)

  # rgb visualization
  rgb = cm(arr)

  # display in app
  st.image(rgb, width=width)

# numpy array
arr = np.random.rand(300,300)

# display numpy array in streamlit app
display_array(arr)

One thing to note is that even in @snehankekre 's excellent example showing matplotlib resizing in action, the final displayed width canā€™t be changed. The image always fills 100% of the width allotted in the column it lives in. Is there any way around that so that i.e. a 3-inch wide image is actually 3 inches wide instead of being widened to 100% after matplotlibā€™s rendering of the image?

2 Likes

Hey @benlindsay, :wave:

Thanks for your patience! Hereā€™s a workaround with 2 additional lines of code. Instead of using st.pyplot, you can convert the matplotlib.figure.Figure object into an image thatā€™s held temporarily in memory, and then display it using st.image like so:

import streamlit as st
import matplotlib.pyplot as plt
from io import BytesIO

cat = ["bored", "happy", "bored", "bored", "happy", "bored"]
dog = ["happy", "happy", "happy", "happy", "bored", "bored"]
activity = ["combing", "drinking", "feeding", "napping", "playing", "washing"]

width = st.sidebar.slider("plot width", 0.1, 25., 3.)
height = st.sidebar.slider("plot height", 0.1, 25., 1.)

fig, ax = plt.subplots(figsize=(width, height))
ax.plot(activity, dog, label="dog")
ax.plot(activity, cat, label="cat")
ax.legend()

buf = BytesIO()
fig.savefig(buf, format="png")
st.image(buf)

matplotlib-resize

Happy Streamlit-ing! :balloon:
Snehan

9 Likes

Awesome, thanks for the workaround! Is there a reason st.image respects the image width but st.pyplot doesnā€™t, or is that something I could submit an issue for? It would be nice to either have a width kwarg in st.pyplot just like st.image and/or change st.pyplotā€™s default behavior to not expand to 100% width, just like st.image

1 Like

I agree! Feel free to submit a new issue :slight_smile:

1 Like

This worked for me very well. You can also change the position of the graph by playing around with the columns.

 col1, col2, col3, col4, col5= st.columns([1,1, 2, 1, 1])
    with col3:
        df = pd.read_csv('dataframe.csv')
        fig, ax = plt.subplots(figsize=(5,4))
        ax = plt.plot(x, y)
        plt.xticks(rotation = 45)
        st.pyplot(fig)
3 Likes

Is this workaround still supposed to work? It doesnā€™t work for me on Streamlit 1.11. :confused:
I am trying to display a figure object via st.pyplot or st.image within st.expander and the image always gets resized to the full width of the expander.

Edit: If I remove the expander the image is still exanded to the surrounding column width.
Edit 2: Also doesnā€™t work if I remove both the surrounding expander and the column.

1 Like

Based on @gulcinvardar 's clever workaround, hereā€™s arbitrary resizing:

input_resize = st.slider("Resize", min_value=0.1, max_value=1.0, step=0.05, value=1.0)
resize = input_resize * 0.999
col1, _ = st.columns((resize / (1 - resize), 1), gap="small")
col1.pyplot(fig)

when fig, axs = plt.subplots(3, 2,figsize=(width, height) )
The parameters are no use again