matplotlib axis redraw on zoom - python

I have a simple graph with a Navigation Tool Bar. When I zoom or pan, the graph is correctly updated, but the axis labels get messed up. Its as if it does not clear the old text out before drawing the new text. So you see the new text written over the old. If I resize the window, it seems to do a full re-draw and fixes the labels. Here is my simple example:
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.backend_bases import key_press_handler
from matplotlib.figure import Figure
from Tix import *
from Tkconstants import *
root = Tk()
f = Figure(figsize=(12,5), dpi=100, frameon=False)
s = f.add_subplot(111, title="test")
x = [0,1,2,3,4,5]
y = [5,2,6,7,3,6]
s.plot(x,y,label="Test")
canvas = FigureCanvasTkAgg(f, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1)
NavigationToolbar2TkAgg(canvas, root)
root.mainloop()
Here is a before:
Here is after panning:

As suggested by Oblivion:
Removing the frameon=False option from f = Figure(figsize=(12,5), dpi=100, frameon=False) solved the issue.

Related

Unable to embed networkx graph using matplotlib in customtk

I'm trying to embed a networkx graph in CustomTk, but the graph doesn't appear. When I use plt.show() I can see the graph in matplotlib pop-up menu, but not in GUI.
import tkinter
import customtkinter
import networkx as nx
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
# Implement the default Matplotlib key bindings.
from matplotlib.backend_bases import key_press_handler
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import numpy as np
root = customtkinter.CTk()
root.title("Embedding in Tk")
fig = Figure(figsize=(5, 4), dpi=100)
G = nx.random_geometric_graph(20, 0.125, seed=896803)
nx.draw_networkx(G, pos=nx.circular_layout(G), node_size=4000, with_labels=True, font_size=20)
plt.style.use('ggplot')
fig = Figure(figsize=(10, 10), dpi=100)
ax = fig.add_subplot(111)
ax = plt.gca()
ax.margins(0.11)
plt.tight_layout()
plt.axis("off")
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
plt.show()
def on_key_press(event):
print("you pressed {}".format(event.key))
key_press_handler(event, canvas, toolbar)
canvas.mpl_connect("key_press_event", on_key_press)
def _quit():
root.quit() # stops mainloop
root.destroy() # this is necessary on Windows to prevent
# Fatal Python Error: PyEval_RestoreThread: NULL tstate
button = customtkinter.CTkButton(master=root, text="Quit", command=_quit)
button.pack(side=tkinter.BOTTOM)
root.mainloop()
# If you put root.destroy() here, it will cause an error if the window is
# closed with the window manager.
plt.show() image:
figure on canvas:
I'm not sure what's the issue when drawing on the canvas.
Thanks in advance
Solution: https://github.com/TomSchimansky/CustomTkinter/issues/971#issuecomment-1371489896
import tkinter
import customtkinter
import networkx as nx
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
# Implement the default Matplotlib key bindings.
from matplotlib.backend_bases import key_press_handler
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import numpy as np
root = customtkinter.CTk()
root.title("Embedding in Tk")
#call fig ax exactly once
fig = Figure(figsize=(5, 4), dpi=100)
ax = fig.add_subplot(111)
ax.margins(0.11)
#call the graphing module
G = nx.random_geometric_graph(20, 0.125, seed=896803)
#draw the graph, note the ax=ax at the end, this is the critical part, matplotlib needs to know onto which axis the graph is drawn
#otherwise it will just draw it in the spyder backend, without a care for your other elements
nx.draw(G, pos=nx.circular_layout(G), node_size=4000, with_labels=True, font_size=20,ax=ax)
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
def _quit():
root.quit() # stops mainloop
root.destroy() # this is necessary on Windows to prevent
# Fatal Python Error: PyEval_RestoreThread: NULL tstate
button = customtkinter.CTkButton(master=root, text="Quit", command=_quit)
button.pack(side=tkinter.BOTTOM)
root.mainloop()
# If you put root.destroy() here, it will cause an error if the window is
# closed with the window manager.

How to change color of matplotlib toolbar in tkinter?

I would like to change the color of the toolbar when making a matplotlib figure in tkinter. I have managed to find and change the color of two parts. There is one remaining.
My code comes directly from https://matplotlib.org/stable/gallery/user_interfaces/embedding_in_tk_sgskip.html?highlight=embedding%20tk with three additional lines to change colors.
import tkinter
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import numpy as np
root = tkinter.Tk()
root.wm_title("Embedding in Tk")
fig = Figure(figsize=(5, 4), dpi=100)
t = np.arange(0, 3, .01)
fig.add_subplot().plot(t, 2 * np.sin(2 * np.pi * t))
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.draw()
color = "#d469a3"
toolbar = NavigationToolbar2Tk(canvas, root, pack_toolbar=False)
toolbar.config(background=color)
toolbar._message_label.config(background=color)
toolbar.update()
button = tkinter.Button(master=root, text="Quit", command=root.quit)
button.pack(side=tkinter.BOTTOM)
toolbar.pack(side=tkinter.BOTTOM)
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
tkinter.mainloop()
This gives me the window:
What is the small, grey rectangle I have pointed out? How do I change its color?
It is an empty label. You can get a reference to it via winfo_children:
print (toolbar.winfo_children()[-2])
# .!navigationtoolbar2tk.!label
And to change its color:
toolbar.winfo_children()[-2].config(background=color)

Scrollbar in tkinter, for matplotlib

I have little experience how to combine matplotlib with tkinter or pyqt.
I need a horizontal scroll bar on the matplotlib chart.
I want to zoom the graph horizontally and scroll the graph from the beginning
to the end of the data that is loaded from the file.
After reviewing the examples, I added a scroll bar.
But she's completely unresponsive to the chart.)
And the process doesn't end when I close the window(how to remove not understood, an example taken from here enter link)
import tkinter
from tkinter import *
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
root = tkinter.Tk()
x = pd.read_csv('file.txt',
index_col='DATE',
parse_dates=True,
infer_datetime_format=True)
z = x.iloc[:, 3].values
N = len(z)
ind = np.arange(N)
fig, ax = plt.subplots()
ax.plot(ind, z)
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
scrollbar = tkinter.Scrollbar(master=root, orient=HORIZONTAL)
scrollbar.pack(side=tkinter.BOTTOM, fill=X)
tkinter.mainloop()
After adding a row
scrollbar["command"] = canvas.get_tk_widget().xview
As pointed out- MaxiMouse.
The graph scrolls, but not along the entire length.
I need the scroll to work on all the data after zooming in. I displayed this at the end of the video.
Put this before the tkinter.mainloop() call:
scrollbar["command"] = canvas.get_tk_widget().xview
canvas.get_tk_widget()["xscrollcommand"] = scrollbar.set

How to realise matplotlib line picker by using opencv?

I would like to pick lines that have been drawn on an image by using cv2.line and do something with them. To realise that I had a look on matplotlibs picker and even found a good example here. As I am going to use tkinter for GUI I added it to my MWE.
Code from example which works fine:
import sys
if sys.version_info[0] < 3:
import Tkinter as Tk
else:
import tkinter as Tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import numpy as np
root = Tk.Tk()
root.iconify()
x = np.linspace(0, 10, 100)
fig, ax = plt.subplots()
for i in range(1, 10):
ax.plot(x, i * x + x, picker=5)
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
def on_pick(event):
event.artist.set_visible(not event.artist.get_visible())
fig.canvas.draw()
fig.canvas.callbacks.connect('pick_event', on_pick)
root.mainloop()
Now my code using OpenCV which does not work:
import sys
if sys.version_info[0] < 3:
import Tkinter as Tk
else:
import tkinter as Tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
import cv2
root = Tk.Tk()
root.iconify()
img = np.zeros([100,100,3],dtype=np.uint8)
img.fill(255)
cv2.line(img,(10,10),(60,90),(100,149,237),2)
fig = Figure()
ax = fig.add_subplot(111)
ax.set_aspect('equal')
ax.plot()
ax.imshow(img)
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
def onpick1(event):
event.artist.set_visible(not event.artist.get_visible())
fig.canvas.draw()
fig.canvas.callbacks.connect('pick_event', onpick1)
root.mainloop()
In both examples onpick1 should set the lines visibility on or off by a single mouse click but it doesn't. My assumption is that it has something to do with the way it is plotted or how I draw the lines (ax.plt vs cv2.line). I would be very happy about any help. Thanks!

animated NetworkX Graph in TkCanvas: background color

For a demonstration of a Graph algorithm i need to draw a networkx graph to a Tkinter Canvas and be able to modify that graph (and the plot) at runtime.
I have pieced together the following code (I hope it is the minimal code leading to my problem, but I'm new to this so I'm not sure):
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import Tkinter as Tk
import networkx as nx
from tkMessageBox import showinfo
root = Tk.Tk()
root.wm_title("Animated Graph embedded in TK")
root.wm_protocol('WM_DELETE_WINDOW', root.quit())
f = plt.figure(figsize=(5,4))
a = f.add_subplot(111)
plt.axis('off')
# the networkx part
G=nx.complete_graph(5)
nx.draw_networkx(G,pos=nx.spring_layout(G),ax=a)
# a tk.DrawingArea
canvas = FigureCanvasTkAgg(f, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
def next_graph():
if G.order():
a.cla()
G.remove_node(G.nodes()[-1])
nx.draw(G, pos=nx.circular_layout(G), ax=a)
canvas.draw()
b = Tk.Button(root, text="next",command=next_graph)
b.pack()
Tk.mainloop()
My problem now is this:
The first display of the graph is like I want it (backgroundcolor-wise), but after you first click 'Next' the backgroundcolor of the graph changes to white. I have tried changing the background color of the figure and the canvas.
I don't even know what brings that change about, I think it is simply drawing to the same canvas twice.
How can I modify the code to have the graph always have the same background color?
On an unrelated note: the root.quit() I added does not help in ending the application properly. This might be stupid on my side, but what did go wrong here?
I think you are very close. If you use nx.draw_networkx() in your event loop then it works (turn off the axis there too).
Here is your example with those modifications and also with a single layout computed at the beginning that is reused in the loop:
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import Tkinter as Tk
import networkx as nx
from tkMessageBox import showinfo
root = Tk.Tk()
root.wm_title("Animated Graph embedded in TK")
# Quit when the window is done
root.wm_protocol('WM_DELETE_WINDOW', root.quit)
f = plt.figure(figsize=(5,4))
a = f.add_subplot(111)
plt.axis('off')
# the networkx part
G=nx.complete_graph(5)
pos=nx.circular_layout(G)
nx.draw_networkx(G,pos=pos,ax=a)
xlim=a.get_xlim()
ylim=a.get_ylim()
# a tk.DrawingArea
canvas = FigureCanvasTkAgg(f, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
def next_graph():
if G.order():
a.cla()
G.remove_node(G.nodes()[-1])
nx.draw_networkx(G, pos, ax=a)
a.set_xlim(xlim)
a.set_ylim(ylim)
plt.axis('off')
canvas.draw()
b = Tk.Button(root, text="next",command=next_graph)
b.pack()
Tk.mainloop()

Categories