Embedding Mapplotlib pie chart into Tkinter Gui Issue - python

Embedding Mapplotlib pie chart into Tkinter Gui help!
I am trying to embed a pie chart into my Tkinter window! So far I already have a frame in mind for the graph to be embedded in, frameChartsLT. This frame also already has a canvas, canvasChartsLT, placed over the entire area of the frame so I was hoping to place it on either of the of these but I keep getting the error.
AttributeError: 'tuple' object has no attribute 'set_canvas'
I checked my entire code but I can't even find anywhere where I wrote set_canvas so I am completely lost. Any help will be truly appreciated! I am also a beginner so the simpler the explanation or fix the better for me haha!
This is the portion of my code!
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
# Some in-between code that sets the frame and canvas on my window
stockListExp = [ 'AMZN' , 'AAPL', 'JETS', 'CCL', 'NCLH']
stockSplitExp = [15,25,40,10,10]
plt.pie(stockSplitExp, radius=1, labels=stockListExp,autopct='%0.2f%%', shadow=True,) # 2 decimal points after plot
figChart1 = plt.pie(stockSplitExp, radius=1, labels=stockListExp,autopct='%0.2f%%', shadow=True)
plt.axis("equal")
chart1 = FigureCanvasTkAgg(figChart1,frameChartsLT)
chart1.get_tk_widget().place(x=10,y=10

You should use matplotlib.figure.Figure instead of pyplot when you combine tkinter with matplotlib. Below with modifications to your code:
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
root = tk.Tk()
frameChartsLT = tk.Frame(root)
frameChartsLT.pack()
stockListExp = ['AMZN' , 'AAPL', 'JETS', 'CCL', 'NCLH']
stockSplitExp = [15,25,40,10,10]
fig = Figure() # create a figure object
ax = fig.add_subplot(111) # add an Axes to the figure
ax.pie(stockSplitExp, radius=1, labels=stockListExp,autopct='%0.2f%%', shadow=True,)
chart1 = FigureCanvasTkAgg(fig,frameChartsLT)
chart1.get_tk_widget().pack()
root.mainloop()

Related

Jupyter Lab interactive image display : issue with widgets arrangements using HBox

I am trying to change content of an image interactively using a slider (e.g. for applying a threshold operation with different values).
My code is as follows:
#%matplotlib ipympl
%matplotlib widget
import matplotlib.pyplot as plt
import cv2
import numpy as np
import ipywidgets as widgets
from ipywidgets import HBox, IntSlider
from IPython.display import Image
def update_lines(change):
ret,thresh2 = cv2.threshold(img_gray,change.new,255,cv2.THRESH_BINARY)
plt.imshow(thresh2)
fig.canvas.flush_events()
image = cv2.imread("Untitled.jpg")
img_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret,thresh2 = cv2.threshold(img_gray,30,255,cv2.THRESH_BINARY)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
slider = IntSlider(
orientation='vertical',
step=1,
value=127,
min=0,
max=255
)
display(HBox([slider, fig.canvas]))
slider.observe(update_lines, names='value')
When executing my code, I have an unexpected behavior: the figure is displayed twice, the first time when I do fig = plt.figure() and the second time when I do display(HBox([slider, fig.canvas])) => see The figure is displayed twice.
How can I display the image only into the HBox ?
When I change the value with the slider, I have the following result => After changing value
It seems that matplotlib cannot directly be persuaded to plot the figure at the figure() call, but it's possible to encapsulate it in an Output widget (taken from here):
output = widgets.Output()
with output:
fig = plt.figure()
# fill figure with content here
display(HBox([slider, output]))
That way, the plot is correctly displayed once.

TypeError: iteration over a 0-d array, using numpy and pydicom

I am trying to create a simple DICOM viewer, in which I plot the image using matplotlib and I want to show that same plot(which is a DICOM image) in tkinter, but when I run the code I get this error. please help. The error occurs when I try to plot a, but I believe it has something to do wuth the way I declared the values of x, y, and p
import pydicom
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
from matplotlib.backends.backend_tkagg import
FigureCanvasTkAgg
from matplotlib.figure import Figure
from tkinter import *
from pydicom.data import get_testdata_files
filename = get_testdata_files('000000.dcm')
dataset = pydicom.dcmread('000000.dcm')
data = dataset.pixel_array
class mclass:
def __init__(self, window):
self.window = window
self.button=Button(window,text="check",command=self.plot)
self.button.pack()
def plot (self):
if 'PixelData' in dataset:
rows = int(dataset.Rows)
cols = int(dataset.Columns)
y=np.array(rows)
x=np.array(cols)
p=np.array(data)
fig = Figure(figsize=(6,6))
a = fig.add_subplot(111)
a.plot(p, range(2+max(y)))
canvas = FigureCanvasTkAgg(fig, master=self.window)
canvas.get_tk_widget().pack()
canvas.draw()
window = Tk()
start = mclass (window)
window.mainloop()
From the look of it your error lies here :
y=np.array(rows)
...
a.plot(p, range(2+max(y)))
You ask for the max(y), but the ds.Rows and ds.Columns you use to instantiate x and y are scalar values (and to be doubly sure you use int(ds.Rows)). This means that both x and y will be a 0-dimensional array and this would explain the thrown error, presumably on max(y). Try :
if 'PixelData' in dataset:
rows = int(dataset.Rows)
cols = int(dataset.Columns)
y=rows
x=cols
p=np.array(data)
fig = Figure(figsize=(6,6))
a = fig.add_subplot(111)
a.plot(p, range(2+y))

Matplotlib y-tick labels not showing

For some reason the y-tick and y-tick labels aren't showing up on my plot. The variable data is a pandas dataframe: rfr_scatter = pd.DataFrame({'Actual':y_test, 'Model Predicted':rfr_predictions})
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
import tkinter as tk
from tkinter import *
def ScatterPlotter(notebooktab, data, test, pred):
f = Figure(figsize=(7,5), dpi=100)
ax1 = f.add_subplot(111, title="Model Performance")
for item in ([ax1.title, ax1.xaxis.label, ax1.yaxis.label] +
ax1.get_xticklabels() + ax1.get_yticklabels()):
item.set_fontsize(8)
item.set_color('black')
markersize = 0.8
alpha = 0.05
line = np.arange(min(test), min(test) + 35, 5)
data.plot.scatter(x='Actual', y='Model Predicted', ax=ax1, s=markersize, alpha=alpha)
ax1.set_xlim((min(test),max(test)))
ax1.set_ylim((pred.min(),pred.max()))
ax1.plot(line,line,clr_red,'--', label = "Perfect")
canvas = FigureCanvasTkAgg(f, notebooktab)
canvas.show()
canvas.get_tk_widget().pack()
And i get this:
I have tried setting the yticks to visible, with no luck. I'm probably missing something simple...
EDIT: removing ax1.set_ylim((pred.min(),pred.max())) gives me a couple marks on the graph, it almost looks like the label is over the text, or the text isn't finishing rendering.
Changing ax1.plot(line,line,clr_red,'--', label = "Perfect") to ax1.plot(line,line,'r--', label = "Perfect") fixed the problem

Two plots, each on its own page in tkinter

I have two plots, which I get as a result of some calculations. I want to show each of them on a separate page. I wanted to use the answer to this question, but I don't know where to insert the code of my plots.
Below is the code for one of the graphs. For the second it is similar.
import matplotlib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
lf = ttk.Labelframe(root, text='Plot №1')
lf.grid(row=0, column=0, sticky='nwes', padx=3, pady=3)
fig = Figure(figsize=(10,5), dpi=100)
ax = fig.add_subplot(111)
df.plot(x='date', y=['col1', 'col2', 'col3', 'col4','col5'], ax=ax)
canvas = FigureCanvasTkAgg(fig, master=lf)
canvas.show()
canvas.get_tk_widget().grid(row=0, column=0)
root.mainloop()
And one more question, how can I show some values in each window for the corresponding plot? For example, on the page for the first plot, I need to show some three values, say
value1 = 5
value2 = 10
value3 = 15
I need to show them next to the corresponding plot.
Any advice, please?

Multiple matplotlib plots in reportlab

I'm trying to put a matplotlib graph onto a reportlab canvas. I can do a simple graph with the code from this question: How to drawImage a matplotlib figure in a reportlab canvas?
But when I try to use subplots or use multiple plots it will not work properly. Doing it this way causes the same image to be plotted twice even when I added things like imgdata.close() or deleting the figure:
from matplotlib.figure import Figure
import cStringIO
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
can = canvas.Canvas()
self.f = Figure()
plot(x,y)
xlabel(xlbl)
ylabel(ylbl)
imgdata=cStringIO.StringIO()
savefig(imgdata,format='png')
imgdata.seek(0)
Image = ImageReader(imgdata)
can.drawImage(Image,100,250, width=400,height=350)
self.g = Figure()
plot(x,y)
xlabel(xlbl)
ylabel(ylbl)
secondimgdata = cStringIO.StringIO()
savefig(secondimgdata,format='png')
secondimgdata.seek(0)
Image2 = ImageReader(secondimgdata)
can.drawImage(Image2,100,150, width=400,height=350)
When trying with subplots it simply produces a blank graph and I did not know where to go with it:
self.f = Figure()
self.a = self.f.add_subplot(111)
self.a.plot(x,y)
self.a2 =self.a.twinx()
self.a2.plot(x,y2,'r')
self.a2.set_ylabel(ylbl2)
self.a.set_xlabel(xlbl)
self.a.set_ylabel(ylbl)
Any solution or advice to this problem would be very much appreciated.
The key is that you must use plt.close() after you're done adding images. Here's a quick example that works for me using seaborn and barplot. Assume I have a dataframe with different data that I want plotted over a few figures.
import matplotlib.pyplot as plt
import seaborn as sns
import cStringIO
from reportlab.platypus import Image
my_df = <some dataframe>
cols_to_plot = <[specific columns to plot]>
plots = []
def create_barplot(col):
sns_plot = sns.barplot(x='col1', y=col, hue='col2', data=my_df)
imgdata = cStringIO.StringIO()
sns_plot.figure.savefig(imgdata, format='png')
imgdata.seek(0)
plots.append(Image(imgdata))
plt.close() # This is the key!!!
for col in cols_to_plot:
create_barplot(col)
for barplot in plots:
story.append(barplot)
This isn't an ideal solution as it has to save the file as an image instead of using StringIO but it works.
import Image as image
from matplotlib.pyplot import figure
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
can = canvas.Canvas()
self.f = figure()
self.a = self.f.add_subplot(2,1,1)
self.a.plot(x,y)
self.a2 =self.a.twinx()
self.a2.plot(x,y2,'r')
self.a2.set_ylabel(ylbl2,color='r')
self.a.set_xlabel(xlbl)
self.a.set_ylabel(ylbl,color='b')
self.f.savefig('plot.png',format='png')
image.open('plot.png').save('plot.png','PNG')
can.drawImage('plot.png',100,250, width=400,height=350)

Categories