Embed a pyplot in a tkinter window and update it - python-2.7

I am trying to write a program that has a pyplot (as in matplotlib.pyplot) within a Tkinter GUI which can be updated. Basically what I want is a program with a Tkinter interface to be displaying some data on a pyplot, then when the program gets some new data I want to update the pyplot to contain the new data.
Here is a minimal example:
import numpy as np
import Tkinter as tk
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
root = tk.Tk()
fig = plt.figure(1)
t = np.arange(0.0,3.0,0.01)
s = np.sin(np.pi*t)
plt.plot(t,s)
canvas = FigureCanvasTkAgg(fig, master=root)
plot_widget = canvas.get_tk_widget()
def update():
s = np.cos(np.pi*t)
plt.plot(t,s)
plt.draw()
plot_widget.grid(row=0, column=0)
tk.Button(root,text="Update",command=update).grid(row=1, column=0)
root.mainloop()
What I expect to happen is, for a window to pop up with a plot containing a sine wave and a button. When I press the button a cosine wave should appear on the plot.
What actually happens when I run the program is that a window pops up with a plot containing a sine wave and a button. However when I press the button nothing happens. The plot does not seem to be updating.
I'm probably making some newbie mistake but I can't find any examples online of doing this sort of thing. What is going wrong here and how would I get what I want?
Any help would be greatly appreciated!

I figured it out, I need to call the draw() method on the figure's canvas attribute in order to get it to redraw, the corrected code is below. Also anyone who is encountering this or similar problems should probably look at matplotlib.animate if they need to be dynamically updating their pyplot
import numpy as np
import Tkinter as tk
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
root = tk.Tk()
fig = plt.figure(1)
plt.ion()
t = np.arange(0.0,3.0,0.01)
s = np.sin(np.pi*t)
plt.plot(t,s)
canvas = FigureCanvasTkAgg(fig, master=root)
plot_widget = canvas.get_tk_widget()
def update():
s = np.cos(np.pi*t)
plt.plot(t,s)
#d[0].set_ydata(s)
fig.canvas.draw()
plot_widget.grid(row=0, column=0)
tk.Button(root,text="Update",command=update).grid(row=1, column=0)
root.mainloop()

Related

Django matplotlib: fname must be a PathLike or file handle

I am trying to display a plot with matplotlib and django following this and this questions, however it seems not working, I tried both solutions and only while using IO i get an empty canvas, but when I try to plot a 'real' plot I get the error in the title.
This is my view:
import django
from matplotlib.backends.backend_agg import FigureCanvasAgg as
FigureCanvas
from matplotlib.figure import Figure
import numpy as np
import matplotlib.pyplot as plt
import io
def mplimage(request):
fig = Figure()
canvas = FigureCanvas(fig)
x = np.arange(-2, 1.5, .01)
y = np.sin(np.exp(2 * x))
plt.plot(x, y)
buf = io.BytesIO()
plt.savefig(buf, format='png')
plt.close(fig)
response = django.http.HttpResponse(content_type='image/png')
canvas.print_png(response)
return response
and here the link in urls.py:
import mpl.views
url(r'mplimage.png', mpl.views.mplimage)
This works if you save the file objects as JPEG (requires PIL) instead of PNG using print_jpg() method instead of print_png().
Change:
response = django.http.HttpResponse(content_type='image/png')
canvas.print_png(response)
To:
response = HttpResponse(content_type='image/jpg')
canvas.print_jpg(response)
from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
import numpy as np
import django
def showimage(request):
fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.add_subplot(111)
x = np.arange(-2,1.5,.01)
y = np.sin(np.exp(2*x))
ax.plot(x, y)
response = HttpResponse(content_type='image/jpg')
canvas.print_jpg(response)
return response

How to make tabular legend using matplotlib and python

I am plotting a choropleth map in python from a shapefile and i want to customize the legend of the plot, i am using the code bellow:
import pandas as pd
import pysal as ps
import geopandas as gp
import numpy as np
import matplotlib.pyplot as plt
pth = 'outcom.shp'
tracts = gp.GeoDataFrame.from_file(pth)
ax = plot_dataframe(tracts, column='Density', scheme='QUANTILES', k=4, colormap=plt.cm.Blues, legend=True)
plt.show()
Besides, i am using a small patch that i found here http://nbviewer.ipython.org/gist/jorisvandenbossche/d4e6efedfa1e4e91ab65 in order to visualize the legend.
here's my result :
But, i need something similar to this :
so my question now, is how can i have a customized legend
You may use a plt.table as a legend.
import matplotlib.pyplot as plt
import numpy as np
valeur = np.array([.1,.45,.7])
text=[["Faible","Ng<1,5" ],["Moyenne","1,5<Ng<2,5"],[u"Elevée", "Ng>2,5"]]
colLabels = ["Exposition", u"Densité"]
tab=plt.table(cellText=text, colLabels=colLabels,
colWidths = [0.2,0.2], loc='lower right',
cellColours=plt.cm.hot_r(np.c_[valeur,valeur]))
plt.show()
In order to link this table to a contourf plot, you may do as follows:
from matplotlib import pyplot as plt
import numpy as np
a = np.sort(np.random.rand(100)).reshape(10,10)*4
levels = np.array([0,1.5,2.5,4])
sm = plt.contourf(a, levels = levels, cmap=plt.cm.hot_r )
text=[["Faible","Ng<1,5" ],["Moyenne","1,5<Ng<2,5"],[u"Elevée", "Ng>2,5"]]
colLabels = ["Exposition", u"Densité"]
col = levels[:-1] + np.diff(levels)/2.
cellcol = sm.cmap(sm.norm(np.c_[col,col]))
tax = plt.gcf().add_axes([0,0,1,1])
tab=tax.table(cellText=text, colLabels=colLabels,
colWidths = [0.2,0.2], loc='lower left',
cellColours=cellcol )
tax.axis("off")
plt.show()

matplotlib graphs not displaying on tkinter window

When I try to graph something with matplotlib in a tkinter window, it simply won't show up. If I remove the tkinter specific part, and just do a basic plt.plot(...) and plt.show() it shows up in my regular text output field. However, in this case I would like it to show up in a tkinter window. I Believe its because I am running this on a mac (macOS 10.12.4), however I cannot figure out how to get it to show up in the tkinter window.
import numpy as np
import Tkinter as tk
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
root = tk.Tk()
fig = plt.figure(1)
t = np.arange(0.0,3.0,0.01)
s = np.sin(np.pi*t)
plt.plot(t,s)
canvas = FigureCanvasTkAgg(fig, master=root)
plot_widget = canvas.get_tk_widget()
def update():
s = np.cos(np.pi*t)
plt.plot(t,s)
plt.show()
plot_widget.grid(row=0, column=0)
tk.Button(root,text="Update",command=update).grid(row=1, column=0)
root.mainloop()
As I said, I believe its due to the fact that I am running on MacOS. Also FYI when I run this a blank tkinter window shows up with the update button, but no graph. The Graph DOES however show up in the regular text output but I want it in the tkinter window for a GUI. Please Help!
You need to update the figure that is already in the tk canvas, instead of showing a new one with plt.show(). In this case there is only one figure open, so plt.plot() will actually work (although it might fail in more complex scenarios). What remains is to redraw the canvas, fig.canvas.draw_idle() after plotting.
import numpy as np
import Tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
root = tk.Tk()
fig = plt.figure(1)
t = np.arange(0.0,3.0,0.01)
s = np.sin(np.pi*t)
plt.plot(t,s)
canvas = FigureCanvasTkAgg(fig, master=root)
plot_widget = canvas.get_tk_widget()
def update():
s = np.cos(np.pi*t)
plt.plot(t,s)
fig.canvas.draw_idle()
plot_widget.grid(row=0, column=0)
tk.Button(root,text="Update",command=update).grid(row=1, column=0)
root.mainloop()
For the future and to be on the save side, try to avoid using pyplot when embedding matplotlib into GUIs. This prevents you from having issues like the one reported here.
import numpy as np
import Tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
root = tk.Tk()
fig = Figure()
ax = fig.add_subplot(111)
t = np.arange(0.0,3.0,0.01)
s = np.sin(np.pi*t)
ax.plot(t,s)
canvas = FigureCanvasTkAgg(fig, master=root)
plot_widget = canvas.get_tk_widget()
def update():
s = np.cos(np.pi*t)
ax.plot(t,s)
fig.canvas.draw_idle()
plot_widget.grid(row=0, column=0)
tk.Button(root,text="Update",command=update).grid(row=1, column=0)
root.mainloop()

Cannot get the pyplot multiple times

I use Embedding Python in C++, in my program, I have to run the python module many times. Unfortunately, the plt.show() only gets the figure one time, the others get the null figure
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Ellipse, Circle
import time
def show(x,y,x1,y1):
fig=plt.figure()
fig.gca().invert_yaxis()
ax1 = fig.add_subplot(111)
cir1 = Circle(xy = (x1, y1), radius=0.02, alpha=0.5)
ax1.add_patch(cir1)
print len(x)
print x1
ax1.set_title('Scatter Plot')
plt.xlabel('X')
plt.ylabel('Y')
ax1.scatter(x,y,c = 'r',marker = 'o')
plt.ion()
plt.show()
time.sleep(1)
plt.close()
return 'ok'

PyPlot not showing on Windows

So I have my backend set to atkgg but pyplot still doesn't show the graph window. Code:
from matplotlib import pyplot as plt
def ex1():
plt.figure(1)
plt.plot([1,1],[2,2],[3,3],[4,4], 'ro')
plt.draw()
plt.show()