29

I understand how to display two plots next to each other (horizontally) in Jupyter Notebook, but I don't know if there is a way to display a plot with a dataframe next to it. I imagine it could look something like this:

enter image description here

However, I'm not able to do this, and whenever I print out the dataframe, it appears below my plot...

Here is a similar question, but I am also outputting plots within this same cell that I want to be vertically oriented.

I currently have this:

# line plots
df_plot[['DGO %chg','DLM %chg']].plot(figsize=(15,5),grid=True)
plt.ylim((-ylim,ylim))

df_plot[['Diff']].plot(kind='area',color='lightgrey',figsize=(15,1))
plt.xticks([])
plt.xlabel('')
plt.ylim((0,ylim_diff))
plt.show()

# scatter plots
plt.scatter(x=df_scat[:-7]['DGO'],y=df_scat[:-7]['DLM'])
plt.scatter(x=df_scat[-7:]['DGO'],y=df_scat[-7:]['DLM'],color='red')
plt.title('%s Cluster Last 7 Days'%asset)
plt.show()

# display dataframe
# display(df_scat[['DGO','DLM']][:10]) <-- prints underneath, not working

enter image description here

Where the red box shows where I want my dataframe to appear. Does anyone have any ideas about how to do this?

Thanks for your thoughts!

1
  • To add to the other solutions on this page, there's an approach that relies on Plotly shared at the bottom of the OP here. Commented Sep 19, 2023 at 15:29

6 Answers 6

21

I'm not aware of how to control the location of where the DataFrame will display directly - but one work around I have used in the past is to render the DataFrame as a matplotlib table and then it should behave like any other matplotlib plot. You can use:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

df = pd.DataFrame()
df['x'] = np.arange(0,11)
df['y'] = df['x']*2

fig = plt.figure(figsize=(8,5))

ax1 = fig.add_subplot(121)
ax1.scatter(x=df['x'],y=df['y'])

ax2 = fig.add_subplot(122)
font_size=14
bbox=[0, 0, 1, 1]
ax2.axis('off')
mpl_table = ax2.table(cellText = df.values, rowLabels = df.index, bbox=bbox, colLabels=df.columns)
mpl_table.auto_set_font_size(False)
mpl_table.set_fontsize(font_size)

enter image description here

Sign up to request clarification or add additional context in comments.

4 Comments

Interesting, that might just work! Out of curiosity, do you need to save the plt as a picture for this to work?
I don't think you need to save the plt as a picture - that is just how I had it set up. You could remove that line if you like. Just calling the function "render_mpl_table(df, 'df')" will display the matplotlib table. A lot of the code is making the table 'pretty' so it might not be needed for your purposes.
This works very well for printing out the dataframe as an ax...do you know how to include it as a subplot? I am using plt.subplot(1,2,1) and plt.subplot(1,2,2) but am not sure how to do the equivalent of plt.ax
OK @DavidYang I figured it out - basically you just have to pull the table outside the function. I also made the table output much more plain.
4

You can always use ipwidgets:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import binom

n = 12[enter image description here][1]
p = 0.5
x = np.arange(0, n+1)

binomial_pmf = binom.pmf(x, n, p)
binomial_cdf = binom.cdf(x, n, p)

import ipywidgets as widgets
from ipywidgets import GridspecLayout

out_box1 = widgets.Output(layout={"border":"1px solid green"})
out_box2 = widgets.Output(layout={"border":"1px solid green"})

with out_box1:
    display(pd.DataFrame({'k':x,'binom pmf':np.round(binomial_pmf,4),'binom cdf':np.round(binomial_cdf,4)}).set_index('k'))
    

with out_box2:
    fig, ax1 = plt.subplots(figsize=(10,6))

    ax2 = ax1.twinx()
    ax1.plot(x, binomial_pmf, 'b-')
    ax2.plot(x, binomial_cdf, 'r-')
    plt.title(f"Binomial Distribution (n={n}, p={p})")
    ax1.grid(color = 'green', linestyle = '--', linewidth = 0.5,b=None, which='major', axis='both')

    plt.xticks(np.arange(min(x), max(x)+1, 1.0))
    ax1.set_ylabel('binomial mdf', color='b')
    ax2.set_ylabel('binomial cdf', color='r')

    plt.show()

grid = GridspecLayout(10, 4)
grid[:, 0] = out_box1
grid[:, 1:4] = out_box2

grid

DataFrame - Plot side by side

1 Comment

Thanks, this seems to be the best option. God bless you!
3

Another possibility is to use the html to order things, following https://stackoverflow.com/a/44923103/4908900.

Here is a working example, (there are probably more elegant ways to do it):

prefix = \
"""
 <!DOCTYPE html>
<html>
<head>
<style>
* {
    box-sizing: border-box;
}

.column {
    float: left;
    width: 33.33%;
    padding: 5px;
}

/* Clearfix (clear floats) */
.row::after {
    content: "";
    clear: both;
    display: table;
}
</style>
</head>
<body>

<h2>title</h2>

<div class="row">
  <div class="column">
"""

suffix = \
"""
  </div>
  <div class="column">
    <img src="pic_file.png" alt="Graph" style="width:100%">
  </div>
</div>
</body>
</html>
"""

df = pd.DataFrame(np.arange(36).reshape((6,6)),columns=['A','B','C','D','E','F'])
ax = df.plot(lw=4)
title = "mock data"
fig = ax.get_figure()
fig.savefig(title+".png")
html = prefix.replace('title', title)+df.to_html()+suffix.replace('pic_file.png', title+".png")
display_html(html, raw=True)

enter image description here

Comments

0

In jupyter-notebook I am limited to table the plot, maybe someone can solve it in my code below. At least it's convenient to plot-zoom and drag as showed in next screenshot:

enter image description here

Code:

import pandas as pd
import matplotlib.pyplot as plt
import mpld3
from IPython.display import display_html
from bs4 import BeautifulSoup
import inspect

plt.ioff() # prevent plots from being displayed in the output of Jupyter Notebook

def getFig():
    iris_df = pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv')
    fig, ax = plt.subplots()
    for species, group in iris_df.groupby('species'):
        ax.scatter(group['sepal_length'], group['sepal_width'], label=species)
    ax.set_xlabel('Sepal Length')
    ax.set_ylabel('Sepal Width')
    ax.legend() 
    return fig
    
def get_html_df(caption="iris_df.groupby('species').mean()"):
    iris_df = pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv')
    html_df = iris_df.groupby('species')[['sepal_length','sepal_width']].mean()\
    .style.set_table_attributes("style='display:inline'")\
    .set_caption(caption)._repr_html_()
    return html_df
    
def main(fig,
         term = 3, # 1, 2 or 3,
         head="Plot", file="deleteme.jpg", caption="HTML-repr's caption tag",
         width=300.0, height=300.0
        ):
       
    html_plot = main_mpld3(fig, width=width, height=height) 
    
    frame = inspect.currentframe()
    args, _, _, values = inspect.getargvalues(frame)
    kwargs = {arg: values[arg] for arg in args}
    [kwargs.pop(key, None) for key in ["fig", "term"]]
    
    match term:
        case 1:
            mpld3.enable_notebook()
            # html_plot not modified
        case 2:
            html_plot = fig2file2html(plt=plt, **kwargs)
        case 3:
            html_plot = fig2file2html(html_plot=html_plot, **kwargs)
    plt.close()
    return html_plot

def main_mpld3(fig, width, height):
    html_plot = mpld3.fig_to_html(fig)
    # print(html_plot)
    
    html_plot = editHTML(html_plot, width, height)
    # print(html_plot)
    return html_plot

def editHTML(html_plot, width, height):
    soup = BeautifulSoup(html_plot, 'html.parser')
    aux = soup.prettify()

    toMatch = '"width": 640.0, "height": 480.0'
    toReplace = f'"width": {width}, "height": {height}' # shows plot, but not inline
    # toReplace = f'"width": {width}, "height": {height}, "style"="display:inline;"' # NOT shows plot
    # toReplace = f'"width": {width}, "height": {height}, "display"="inline"' # NOT shows plot
    modified_html = aux.replace(toMatch, toReplace)
    
    # no effect to inline
    toMatch = '"drawstyle": "default"'
    toReplace = '"drawstyle": "inline"'
    modified_html = modified_html.replace(toMatch, toReplace)
    
    # no effect to inline
    toMatch = '<style>\n</style>'
    toReplace = ''
    modified_html = modified_html.replace(toMatch, toReplace)
    
    soup = BeautifulSoup(modified_html, 'html.parser')
    aux = soup.prettify()
    
    return aux

def fig2file2html(plt=None, html_plot=None, head="Plot", file="deleteme.jpg", caption="HTML-repr's caption tag",
                 width=300.0, height=300.0):
    if (plt is None) and (html_plot is None):
        return Error
    if plt is not None:
        plt.savefig(file)
        html_img = f'<img src={file} alt="" border=3 height={height} width={width}></img>'
    if html_plot is not None:
        hr = 4*"&nbsp;"
        html_img = hr + html_plot + hr
    
    # <img> --> no inline
    html_plot= html_img.replace("<img", "<img style='display:inline ")
    
    # <div> --> no inline
    html_plot= f"""<div style='display:inline'>
    {html_img}
    </div>
    """
    
    # <table> --> YES inline
    html_plot= f"""<table style='display:inline'>
    <caption>{caption}</caption>
    <tr><th>{head}</th><tr>
    <tr><td>
    {html_img}
    </td></tr>
    </table>
    """
    return html_plot


def test01():
    fig = getFig()
    html_df = get_html_df()
    html_plot = main(fig)
    
    print("2 dfs inline:")
    display_html(html_df + html_df, raw=True) # YES success!
    print("df and plot inline:")
    display_html(html_df + html_plot, raw=True) # inline if term=3 or term=2

def test02():
    fig = getFig()
    html_df = get_html_df(caption="")
    html_plot = main(fig,
                     term = 3, # 1, 2 or 3
                     head="", file="deleteme.jpg", caption="",
                     width=650.0, height=650.0,
                    )
    display_html(html_df + html_plot, raw=True)
#test01()
test02()

Comments

0
enter image description hereimport mpld3
fig, ax1= plt.subplots(nrows = 1, ncols=1, figsize=(5,3), layout ='constrained');
ax1.hist(df.GR,cumulative=0,histtype ='bar', bins=50, density=True, align='mid', color='green', alpha=0.5, edgecolor = "black");
plt.close(fig) # prevenir que se muestre la figura en el resultado de la celda



display(HTML(f"""
<div style="display: flex; justify-content: center;">
    <div>{GR_stats_df.to_html()}</div>
    <div>{mpld3.fig_to_html(fig)}</div>
</div>
"""))

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
-1

You can use %matplotlib inline then just simply write the code ex df.head() plt.plot(df['X']) so %matplotlib inline will plot the data frame as well as the plot in one cell

1 Comment

Please format your code and add an easy-to-understand example. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.