Repository: streamlit/streamlit

Issue:
Top Half of Seaborn Chart Title Gets Cut Off
# Summary
When adding a title to a seaborn or perhaps MATPLOTLIB chart (have not tested with MATPLOTLIB yet) chart, the top half of the title is cut off or not displayed

```
# Steps to reproduce
import matplotlib.pyplot as plt
import seaborn as sns
import streamlit as st

mpg = sns.load_dataset("mpg")
option = st.sidebar.multiselect('Choose country of origin:', mpg.origin.unique()
sns.relplot(x="horsepower", y="mpg", hue="origin", size="weight", sizes=(40, 400), alpha=0.5, palette="muted", height=6, data=mpg.query("origin == @option"))
plt.title('MPG vs Weight by Country of Origin')
st.pyplot()
```

## Expected behavior:
seaborn chart title to be fully visible

## Actual behavior:
Top half of seaborn chart title is cut off

## Is this a regression?
That is, did this use to work the way you expected in the past?  First time using streamlit, so not sure if worked in the past
yes?  maybe?

# Debug info
- Streamlit version: 0.47.4
- Python version: 3.7
- Using Conda
- OS version: Windows 10
- Browser version: Chrome version 77



Discussion:
I apologize, I left out a crucial line: st.write(mpg.query("origin == @option"))  just before where the seaborn chart gets rendered and that appears to be the problem.  It appears when rendering the dataframe above the seaborn chart, it appears that the bottom portion of the rendered dataframe overlaps or covers the top portion of the seaborn chart.
Out of curiosity, I removed the dataframe and added a markdown title above the seaborn chart, the seaborn chart title still gets cut off.  So perhaps anything rendered above the seaborn chart title will cut off or overlap over the chart title.  As a workaround, I guess users can remove the seaborn chart title and just use markdown title as the title for the seaborn chart.
Confirmed still an issue.

<img width="719" alt="Screen Shot 2020-02-13 at 3 58 58 PM" src="https://user-images.githubusercontent.com/98836/74489304-c5841b00-4e79-11ea-9adf-f89f3b147b0f.png">

This looks to be a problem with Seaborn. Running this independently of streamlit produces the same issue. 

```
import matplotlib.pyplot as plt
import seaborn as sns

mpg = sns.load_dataset("mpg")
sns.relplot(
    x="horsepower", y="mpg",
    hue="origin", size="weight", sizes=(40, 400),
    alpha=0.5, palette="muted", height=6,
    data=mpg.query("origin == 'usa'"))
plt.title('MPG vs Weight by Country of Origin')
plt.show()
```
![Figure_1](https://user-images.githubusercontent.com/24946400/81953090-423ba800-95d5-11ea-8aab-fe6b7a708589.png)
Did we file an issue with Seaborn?
Just did! [Seaborn #2072](https://github.com/mwaskom/seaborn/issues/2072)
Cool! Gonna move this to the icebox for now. Let's re-visit if/when Seaborn fixes the bug. 

It's only a test dependency of ours but looks like the Cypress tests for Seaborn are currently `flaky` so we can revisit them after the fix.
Turns out for matplotlib, you need to configure the chart appropriately to make room for the title. We're evaluating if this is something we'd like to manipulate as part of our library or return the output as is.

In the meantime, @pybokeh if this is still an issue, there are two ways to resolve this. For more details, please see [Seaborn #2072](https://github.com/mwaskom/seaborn/issues/2072)

### Set the bbox to `tight`
```st.pyplot(bbox_inches="tight")```

### Make room for the chart
```import matplotlib.pyplot as plt
import seaborn as sns

mpg = sns.load_dataset("mpg")
g = sns.relplot(
    x="horsepower",
    y="mpg",
    hue="origin",
    size="weight",
    sizes=(40, 400),
    alpha=0.5,
    palette="muted",
    height=6,
    data=mpg.query("origin == 'usa'")
)
g.fig.subplots_adjust(top=.95)
g.ax.set_title('MPG vs Weight by Country of Origin')
st.pyplot()
```


Looks like this is fine in Jupyter. Exploring if there's a simple change we can apply to st.pyplot to inherit all the behavior from Jupyter 

Initial findings:
- Jupyter uses the Matplotlib backend called [nbagg](https://github.com/matplotlib/matplotlib/blob/002b27e352b90410c9840233b6ce42c54e291403/lib/matplotlib/backends/backend_nbagg.py)
- Jupyter used to have a special function that sets up Matplotlib, possibly [matplotlib](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-matplotlib)
It looks like Jupyter's backend only addresses charts displayed inline. In streamlit, we're sending over a saved image. While we could update our matplotlib backend to align with Juptyer's (`module://ipykernel.pylab.backend_inline`), it would not handle the necessary resizing of the chart to accommodate for a title.

Sample code:
```
import matplotlib.pyplot as plt
import seaborn as sns

mpg = sns.load_dataset("mpg")
sns.relplot(
    x="horsepower", y="mpg",
    hue="origin", size="weight", sizes=(40, 400),
    alpha=0.5, palette="muted", height=6,
    data=mpg.query("origin == 'usa'"))
plt.title('MPG vs Weight by Country of Origin')
plt.savefig('jupyter')
```

Revisiting with the team to determine if our library should handle it. 
Added the docs label here...since this is a quirk of matplotlib, best solution in the interim is probably just to highlight that it happens and the solution is usually `st.pyplot(bbox_inches="tight")`

Resolving patch:
diff --git a/lib/streamlit/elements/pyplot.py b/lib/streamlit/elements/pyplot.py
--- a/lib/streamlit/elements/pyplot.py
+++ b/lib/streamlit/elements/pyplot.py
@@ -46,7 +46,7 @@ def marshall(coordinates, new_element_proto, fig=None, clear_figure=True, **kwar
     # Normally, dpi is set to 'figure', and the figure's dpi is set to 100.
     # So here we pick double of that to make things look good in a high
     # DPI display.
-    options = {"dpi": 200, "format": "png"}
+    options = {"bbox_inches": "tight", "dpi": 200, "format": "png"}
 
     # If some of the options are passed in from kwargs then replace
     # the values in options with the ones from kwargs


Test patch: