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))
1 Like

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

2 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?

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

1 Like

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

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

1 Like