How to edit table data with interactive event in matplotlib - python

A table is created in a figure. Now I want to edit the table after double click at the cell, adding, deleting or revising the data in this cell. Just like the edit function in Excel. My python version is 3.64. Codes are following:
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
# Hide axes
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
# Table from Ed Smith answer
clust_data = [[1,1,7]]
collabel=("col 1", "col 2", "col 3")
ax.table(cellText=clust_data,colLabels=collabel,loc='center')
plt.show()

It seems that you this is not easy to achieve using pure matplotlib functional.
You should consider looking at qgrid module, which provides interactive Excel-like table editing in Jupyter Notebook.
Then, if you want to change your graph accordingly, you will need to create some interaction with the table. ipywidgets can really help you with that.

Related

Seaborn heatmap: annotate with clickable hyperlink

Is there a way to annotate a seaborn heatmap with a clickable hyperlink in Jupyter notebook? The documentation explains clearly how to create simple annotated heatmaps. My question is, is it possible to make the annotations clickable in Jupyter?
In principle the answer creating a clickable hyperlink in a matplotlib figure in jupyter is given in Python matlplotlib add hyperlink to text. To apply it to a heatmap, one would need to add the texts manually. I.e. one would in that case not use seaborn to create the heatmap, but matplotlib directly.
The following creates an annotated heatmap where you can click on any number and be directed to the respective page on wolframalpha.
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import set_matplotlib_formats
set_matplotlib_formats("svg")
data = np.random.randint(1,50, size=(3,3))
fig, ax = plt.subplots()
im=ax.imshow(data)
fig.colorbar(im)
for (j,i), x in np.ndenumerate(data):
url = "https://www.wolframalpha.com/input/?i={}".format(x)
ax.annotate(x, xy=(i,j), ha="center", va="center",
url=url, bbox=dict(color='w', alpha=1e-6, url=url))

How to show specific axes in a figure

I created a figure which has 2 axes, how can I plot specific axes(eg,ax[0]) rather than plot both axes? When I input fig in the end both axes will appear together. What code should I write if I just want ax[0] be displayed for example?
fig,ax=plt.subplots(2)
x=np.linspace(1,10,100)
ax[0].plot(x,np.sin(x))
ax[1].plot(x,np.cos(x))
fig
I interprete that you are using Jupyter notebook. You may then use the fact that invisble axes parts of a figure will be cropped with the matplotlib inline backend.
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
fig,ax=plt.subplots(2);
x=np.linspace(1,10,100)
ax[0].plot(x,np.sin(x))
ax[1].plot(x,np.cos(x))
Now to only show the second subplot, you can set the first invisible,
ax[0].set_visible(False)
fig
If you then want to only show the first subplot, you need to set it visible again and the second one invisible
ax[0].set_visible(True)
ax[1].set_visible(False)
fig

Include output from %matplotlib notebook backend as SVG in ipynb

This answer from a few years ago shows how you can make jupyter notebook create graphs as svg. The solution is to tell the InlineBackend to use svg as output.
import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
plt.plot(...)
This will cause all images to be in svg format inside the notebook as well as in the produced ipynb file; the file will have a line like
"data": { "image/svg+xml": [ "<?xml .....
in it.
The problem is now that this does not work if the %matplotlib notebook backend is used. %config InlineBackend does not change anything for the notebook backend, hence the output file contains a PNG image
"data": { "text/html": [ "<img src=\"data:image/png;base64,iVBORw0....
So the question is: How do I get the ipynb file to include a static version of the plot that is created with the %matplotlib notebook backend as SVG image?
There is a small comment by #mark jay from one month ago, who wanted to do exactly what I would like to do now, but there is no answer or hint to that comment.
In my code I have plotted directly from the dataframe:
%matplotlib notebook
import pandas as pd
df = pd.read_sql(sql1, connection)
...
...
df.plot(subplots=True, kind='bar')
This functions perfectly well without importing matplotlib.pyplot but it also can't be coerced to create the graphic as an svg. I suppose if the base case would work, I could modify the plotting code so it did not involve pandas or dataframes.
Since apparently even after a bounty period noone was able to provide a solution, a workaround may be the following.
Create you notebook with %matplotlib notebook. Once you're satisfied with the result, save it.
Use a copy of it and replace %matplotlib notebook with
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
Rerun the complete notebook. Save the result.
Open the resulting ipynb file in a text editor and replace the previous two lines again with %matplotlib notebook.
The final result will be a ipynb with svg images. But once opened and run, it will use the notebook backend for figure creation.
From whatI understand from reading about matplotlib backends, nbagg, which is called using %matplotlib notebook uses the Agg (Anti-Grain Geometry) render which is not capable of rendering vector graphics. Unfortunately this is the only out of the box way of using an interactive inline backend for Jupyter.
Docs Link https://matplotlib.org/faq/usage_faq.html#what-is-interactive-mode
Similar Answer How to make matplotlibs nbagg backend generate SVGs?
If you don't need the interactivity just keep use
import pandas as pd
from IPython.display import SVG, display
from numpy import ndarray
def svg_add(chart, size=(4,4), dpi=100):
"""Takes a chart, optional tuple of ints for size, int for dpi
default is 4 by 4 inches with 100 dpi"""
if type(chart) == ndarray:
fig = chart[0].get_figure()
fig.set_size_inches(size)
fig.savefig("mybar.svg", dpi=dpi)
display(SVG(filename='mybar.svg'))
else:
fig = chart.get_figure()
fig.set_size_inches(size)
fig.savefig("mybar.svg", dpi=dpi)
display(SVG(filename='mybar.svg'))
then
df = pd.DataFrame([[2,5]],columns=['a','b'])
bar_chart = df.plot(subplots=False, kind='bar')
svg_add(chart=bar_chart,size=(3,3),dpi=100)
#or
#svg_add(bar_chart,(3,3),100)

unwanted blank subplots in matplotlib

I am new to matplotlib and seaborn and is currently trying to practice the two libraries using the classic titanic dataset. This might be elementary, but I'm trying to plot two factorplots side by side by inputting the argument ax = matplotlib axis as shown in the code below:
import matploblib.pyplot as plt
import seaborn as sns
%matplotlib inline
fig, (axis1,axis2) = plt.subplots(1,2,figsize=(15,4))
sns.factorplot(x='Pclass',data=titanic_df,kind='count',hue='Survived',ax=axis1)
sns.factorplot(x='SibSp',data=titanic_df,kind='count',hue='Survived',ax=axis2)
I was expecting the two factorplots side by side, but instead of just that, I ended up with two extra blank subplots as shown above
Edited: image was not there
Any call to sns.factorplot() actually creates a new figure, although the contents are drawn to the existing axes (axes1, axes2). Those figures are shown together with the original fig.
I guess the easiest way to prevent those unused figures from showing up is to close them, using plt.close(<figure number>).
Here is a solution for a notebook
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
%matplotlib inline
titanic_df = pd.read_csv(r"https://github.com/pcsanwald/kaggle-titanic/raw/master/train.csv")
fig, (axis1,axis2) = plt.subplots(1,2,figsize=(15,4))
sns.factorplot(x='pclass',data=titanic_df,kind='count',hue='survived',ax=axis1)
sns.factorplot(x='sibsp',data=titanic_df,kind='count',hue='survived',ax=axis2)
plt.close(2)
plt.close(3)
(For normal console plotting, remove the %matplotlib inline command and add plt.show() at the end.)

(Matplotlib, python) long subplots, scrolling

I would like to create a pdf file [by using plt.savefig("~~~.pdf")]
containing lots of (about 20) subplots
each of which is drawing timeseries data.
I am using a matplotlib library with python language.
Each subplot may be long, and I want to put the subplots
horizontally.
Therefore, the figure should be very long (horizontally), so the horizontal scroll bar should be needed!
Is there any way to do this?
some example code will be appreciated!
The following is my sample code.
I just wanted to draw 10 sine graphs arranged horizontally
and save it as pdf file.
(but I'm not pretty good at this. so the code may looks to be weird to you.. :( )
from matplotlib import pyplot as plt
import numpy as np
x=np.linspace(0,100,1000)
y=np.sin(x)
numplots=10
nr=1
nc=numplots
size_x=nc*50
size_y=size_x*3/4
fig=plt.figure(1,figsize=(size_x,size_y))
for i in range(nc):
ctr=i+1
ax=fig.add_subplot(nr,nc,ctr)
ax.plot(x,y)
plt.savefig("longplot.pdf")
plt.clf()
Thank you!
You should do that using the backend "matplotlib.backends.backend_pdf". This enables you to save matplotlib graphs in pdf format.
I have simplified your code a bit, here is a working example:
from matplotlib import pyplot as plt
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
x = np.linspace(0,100,1000)
y = np.sin(x)
nr = 10
nc = 1
for i in range(nr):
plt.subplot(nr, nc, i + 1)
plt.plot(x, y)
pdf = PdfPages('longplot.pdf')
pdf.savefig()
pdf.close()
I hope this helps.
In the link below there is a solution, which can help you, since it was helpful to me either.
Scrollbar on Matplotlib showing page
But if you have many subplots, I am afraid your problem won't be solved. Since it will shrink each graph anyway. In that case it will be better to break your graphs into smaller and separate parts.

Categories

Resources