How to display matplotlib numpy.ndarray in tkinter - python-3.x

I want to display numpy.ndarray matplotlib in tkinter.
I tried in backend it works fine, but does not display in tkinter and show the canvas with graph empty.instead the code below display the picture in separate window as pop-up. How can I display it in the canvas and inside the window?
from tkinter import *
from tkinter import ttk
import numpy as np
import pandas as pd
from scipy.stats import norm
import requests
from pandas_datareader import data as wb
import matplotlib.pyplot as plt
%matplotlib inline
from yahoofinancials import YahooFinancials
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib
matplotlib.use('TkAgg')
class Scr:
def __init__(self, master):
master.geometry('300x300+120+60')
self.frame_content = ttk.Frame(master)
self.frame_content.pack()
tickers = ['AAPL']
new_data = pd.DataFrame()
for t in tickers :new_data[t] = wb.DataReader(t, data_source ='yahoo', start = '2004-1-1')['Adj Close']
lr = np.log(1+new_data.pct_change())
var=lr.var()
mean=lr.mean()
drift = mean-(0.5 * var)
stdv=lr.std()
norm.ppf(0.95)
x = np.random.rand(10,2)
norm.ppf(x)
Ze=norm.ppf(np.random.rand(10,2))
t_intervals =1000
iteration=10
daily_returns=np.exp(drift.values + stdv.values * norm.ppf(np.random.rand(t_intervals,iteration)))
S=new_data.iloc[-1]
am = np.zeros_like(daily_returns)
am[0] = S
for t in range (1, t_intervals):
am[t]=am[t-1] * daily_returns[t]
graph3=ttk.Frame(master)
graph3.pack()
graph3.place(x=750,y=550)
plt.plot(am)
fig3 = matplotlib.pyplot.Figure(figsize=(6,6))
canvas3 = FigureCanvasTkAgg(fig3, graph3)
canvas3.get_tk_widget().pack()
ax3 = fig3.add_subplot(211)
am.plot(kind='line', legend=True, ax=ax3).grid(linestyle = 'dashed')
def main():
root = Tk()
scr = Scr(root)
root.mainloop()
if __name__ == "__main__": main()
The error message I got is :
'numpy.ndarray' object has no attribute 'plot'

am is numpy.ndarray
am = np.zeros_like(daily_returns)
and it doesn't have am.plot().
But pandas.DataFrame has it. You have to convert am to DataFrame
df = pd.DataFrame(am)
df.plot(kind='line', legend=True, ax=ax3).grid(linestyle = 'dashed')
(and you can remove plt.plot(am))
And remove graph3.place(x=750,y=550) which moves plot far away and it is invisible. You have to manually resize window to see plot.
from tkinter import *
from tkinter import ttk
import numpy as np
import pandas as pd
from scipy.stats import norm
import requests
from pandas_datareader import data as wb
import matplotlib.pyplot as plt
from yahoofinancials import YahooFinancials
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib
matplotlib.use('TkAgg')
class Scr:
def __init__(self, master):
master.geometry('300x300+120+60')
self.frame_content = ttk.Frame(master)
self.frame_content.pack()
tickers = ['AAPL']
new_data = pd.DataFrame()
for t in tickers:
new_data[t] = wb.DataReader(t, data_source='yahoo', start='2004-1-1')['Adj Close']
lr = np.log(1+new_data.pct_change())
var = lr.var()
mean = lr.mean()
drift = mean-(0.5 * var)
stdv = lr.std()
norm.ppf(0.95)
x = np.random.rand(10,2)
norm.ppf(x)
Ze = norm.ppf(np.random.rand(10,2))
t_intervals =1000
iteration = 10
daily_returns = np.exp(drift.values + stdv.values * norm.ppf(np.random.rand(t_intervals,iteration)))
am = np.zeros_like(daily_returns)
am[0] = new_data.iloc[-1]
for t in range (1, t_intervals):
am[t]=am[t-1] * daily_returns[t]
graph3 = ttk.Frame(master)
graph3.pack()
#graph3.place(x=750,y=550)
fig3 = matplotlib.pyplot.Figure(figsize=(6,6))
canvas3 = FigureCanvasTkAgg(fig3, graph3)
canvas3.get_tk_widget().pack()
ax3 = fig3.add_subplot(211)
df = pd.DataFrame(am)
df.plot(kind='line', legend=True, ax=ax3).grid(linestyle = 'dashed')
def main():
root = Tk()
scr = Scr(root)
root.mainloop()
if __name__ == "__main__":
main()

Related

I am getting unwanted loading of previous plot axis points to the next plot in PyQt5 matplotlib

I am trying to update the plot after a new file is selected, but the new plot that is generated it has the points that are of previous plot on both X and Y axis, I don't want to those previous points, please anyone explain why this happens so and how to get rid of this. Images are shown here, previous plot is
after this I choose to select second file with different data to plot it, next plot is this image
The code I am trying to build is
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from PyQt5.QtWidgets import (QApplication, QWidget, QFileDialog, QPushButton, QLabel, QGridLayout, QVBoxLayout, QLineEdit)
from Bio import SeqIO
from collections import Counter
from Bio.SeqUtils import molecular_weight
from Bio.SeqUtils import GC
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("DNA Sequence Analysis - Prashik Lokhande")
self.setLayout(QVBoxLayout())
my_label = QLabel("DNA Sequence Analysis from the FASTA Database, (FASTA databse can be found on NCBI website). Build by Prashik Lokhande")
self.layout().addWidget(my_label)
self.visualize()
self.show()
def visualize(self):
container = QWidget()
container.setLayout(QGridLayout())
label_1 = QLabel("PLease Select FASTA file")
button_1 = QPushButton("Select file", clicked = lambda: self.get_plot())
gc_count_label = QLabel("GC Count = ")
self.gc_count_field = QLabel("0")
self.canvas = FigureCanvas(plt.Figure(figsize=(10, 4)))
container.layout().addWidget(label_1, 0,0)
container.layout().addWidget(button_1, 1,0)
container.layout().addWidget(gc_count_label, 2, 1)
container.layout().addWidget(self.gc_count_field, 3, 1)
container.layout().addWidget(self.canvas, 2, 0, 3, 1)
self.layout().addWidget(container)
def get_plot(self):
filepath, _ = QFileDialog.getOpenFileName(self, 'select FASTA file')
record = SeqIO.read(filepath,"fasta")
dna = record.seq
mrna = dna.transcribe()
protein = mrna.translate()
self.mol_weight = molecular_weight(dna)
gc = GC(dna)
self.gc_count_field.setText(str(gc))
pr_freq = Counter(protein)
self.ax = self.canvas.figure.subplots()
self.ax.bar(pr_freq.keys(), pr_freq.values())
self.ax.set_title("Amino Acid Contents in the sequence (X-axis Amino acids, Y-axis frequency)")
app = QApplication([])
mw = MainWindow()
app.exec_()
Every time you press the button, self.ax = self.canvas.figure.subplots() will create a new set of axes and add it at the (0,0) position in the grid of previously created subplots. Since all subplots are placed at the same position in the grid they all overlap. To get around this, you could just create one set of axes in MainWindow.__init__, and reuse this one in MainWidon.get_plot, i.e.
class MainWindow(QWidget):
def __init__(self):
....
self.ax = self.canvas.figure.subplots()
def get_plot(self):
....
# clear previous plot
self.ax.clear()
self.ax.bar(pr_freq.keys(), pr_freq.values())
....

How can I access images from qrc.py into reportlab?

I have converted "image_fonts.qrc" into image_fonts_rc.py file. It has one image named as "image.png"
How can I use an image into reportlab PDF in Python from qrc.py file.
File image_fonts.qrc
<RCC>
<qresource prefix="image_fonts">
<file>image.png</file>
<file>logo.png</file>
</qresource>
</RCC>
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/image_fonts/logo.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
I used above the lines, but I get an error. Please find the below error.
TypeError: expected str, bytes or os.PathLike object, not QIcon
Minimal Example:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSql import *
from PyQt5 import uic
import sys
from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, PageTemplate, TableStyle, Paragraph, Image, Spacer, Frame, Paragraph, Flowable
import image_fonts_rc
class UI(QMainWindow):
def __init__(self):
super(UI, self).__init__()
uic.loadUi("test_images.ui", self)
self.show()
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/image_fonts/logo.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
doc = SimpleDocTemplate("images.pdf", pagesize=A4, rightMargin=40, leftMargin=40, topMargin=20, bottomMargin=20, title ="Images")
width, height = A4
document = []
logo = icon
imgw = imgh = 80
im = (Image(logo, width=imgw, height=imgh))
document.append(im)
doc.build(document)
app = QApplication(sys.argv)
window = UI()
app.exec_()
It is not necessary to use QPixmap or QIcon but you must get the bytes from the image as in my previous answer:
from io import BytesIO
from PyQt5 import QtCore
from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, Image
import image_fonts_rc
def convert_qrc_to_bytesio(filename):
file = QtCore.QFile(filename)
if not file.open(QtCore.QIODevice.ReadOnly):
raise RuntimeError(file.errorString())
return
f = BytesIO(file.readAll().data())
return f
doc = SimpleDocTemplate(
"images.pdf",
pagesize=A4,
rightMargin=40,
leftMargin=40,
topMargin=20,
bottomMargin=20,
title="Images",
)
width, height = A4
document = []
logo = convert_qrc_to_bytesio(":/image_fonts/logo.png")
imgw = imgh = 80
im = Image(logo, width=imgw, height=imgh)
document.append(im)
doc.build(document)

real-time plotting to a TK window using python3

I am trying to plot in real-time to a tkinter window in python3.
I am attempting to wrap my window in a class.
my code shows the graph, but data is not being plotted. Here is the code:
#! /usr/bin/python3
# -*- coding: utf-8 -*-
import sys
import matplotlib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
import tkinter
import time
import numpy as np
matplotlib.use("TkAgg")
class Window(tkinter.Frame):
def __init__(self, master = None):
tkinter.Frame.__init__(self, master)
self.master = master
self.master.grid()
self.fig = Figure(figsize=(5,5), dpi=100)
self.ax = self.fig.add_subplot(111)
self.t, self.y = [], []
self.init_window()
self.ani = animation.FuncAnimation(self.fig, self.animate, interval=1000)
def init_window(self):
# set window title
self.master.title("PlotSomething")
# run show_graph
self.show_graph()
def animate(self):
self.t.append(time.time())
self.y.append(np.random.random())
self.ax.clear()
self.ax.plot(self.t,self.y)
def show_graph(self):
canvas = FigureCanvasTkAgg(self.fig, self.master)
canvas.get_tk_widget().grid(row=1, column=1)
canvas.draw()
def client_exit(self):
sys.exit()
def main(args):
root = tkinter.Tk()
app = Window(root)
root.mainloop()
return 0
if __name__=="__main__":
sys.exit(main(sys.argv[1:]))
Please let me know what the issue is.
Bonus if you can help me get the real-time plot stuff into a separate class that I can call with my tkinter window.
I obviously need some learning on how to create and call classes using tkinter.
As always thank you for your support!

How to display multicursor on a QTabWidget?

The multicursor example
The question is : If I want the plot to be displayed on a tab of the QTabWidget,how to make the MultiCursor works?
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
import numpy as np
import sys
from matplotlib.gridspec import GridSpec
from matplotlib.widgets import MultiCursor
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
class MainWindow(QMainWindow):
def __init__(self):
super().__init__(flags=Qt.Window)
self.setFont(QFont("Microsoft YaHei", 10, QFont.Normal))
self.setMinimumSize(1550, 950)
self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
centralwidget = QWidget(flags=Qt.Widget)
centralwidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.setCentralWidget(centralwidget)
self.tabview = QTabWidget()
self.tabview.currentChanged.connect(self.onchange)
self.chart_widget0 = QWidget()
self.chart_widget1 = QWidget()
self.dc0 = my_Canvas(self.chart_widget0, width=20, height=8, dpi=100)
self.dc1 = my_Canvas(self.chart_widget1, width=20, height=8, dpi=100)
self.tabview.addTab(self.dc0, "MultiCursor")
self.tabview.addTab(self.dc1, "Cursor")
toplayout = QHBoxLayout()
toplayout.addWidget(self.tabview)
centralwidget.setLayout(toplayout)
def onchange(self,i):
if i == 0:
self.dc0.update_figure()
elif i == 1:
self.dc1.update_figure()
class my_Canvas(FigureCanvas):
def __init__(self, parent=None, width=10, height=7, dpi=100):
self.fig = plt.figure(figsize=(width, height), dpi=dpi)
gs = GridSpec(2, 1, height_ratios=[3, 1])
self.axes1 = plt.subplot(gs[0])
self.axes2 = plt.subplot(gs[1])
self.compute_initial_figure()
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
def compute_initial_figure(self):
self.axes1.cla()
self.axes2.cla()
def update_figure(self):
t = np.arange(0.0, 2.0, 0.01)
s1 = np.sin(2*np.pi*t)
s2 = np.sin(4*np.pi*t)
self.axes1.plot(t, s1)
self.axes2.plot(t, s2)
multi = MultiCursor(self.fig.canvas, (self.axes1, self.axes2), color='r', lw=1)
self.draw()
if __name__ == '__main__':
app = QApplication(sys.argv)
w1 = MainWindow()
w1.show()
sys.exit(app.exec_())
How to modify the code to make the MultiCursor works, and could I control the display of the cursor by key or mousebutton click?
Further more, how to display the coordinate with the cursor?
As the Multicursor documentation tells us,
For the cursor to remain responsive you must keep a reference to it.
The easiest way is to make it a class variable,
self.multi = MultiCursor(...)

get the zdata with event from a orthoviewer of medical image

I want get the zdata, from navigation toolbar, when I load a .nii file. I want do that with the event def _onclick(event):
import matplotlib
matplotlib.use('TkAgg')
from tkinter import filedialog
from tkinter import *
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from nibabel.loadsave import read_img_data
from nibabel.loadsave import load as load_nii
from viewers import OrthoSlicer3D
from matplotlib.figure import Figure
import numpy as np
import sys
if sys.version_info[0] < 3:
import Tkinter as Tk
else:
import tkinter as Tk
root = Tk.Tk()
root.wm_title("Orthoslicer3D for brain segmentation")
f = Figure()
sagital = f.add_subplot(221)
sagital.set_position([0,0,0.5,0.5])
sagital.set_axis_off()
coronal = f.add_subplot(222)
coronal.set_axis_off()
coronal.set_position([0,0.5,0.5,0.5])
axial = f.add_subplot(223)
axial.set_position([0.5,0.5,0.5,0.5])
axial.set_axis_off()
axes = (sagital, coronal, axial)
# a tk.DrawingArea
canvas = FigureCanvasTkAgg(f, master=root)
canvas.get_tk_widget().pack(side=Tk.RIGHT, fill=Tk.BOTH, expand=1)
toolbar = NavigationToolbar2TkAgg(canvas, root)
toolbar.update()
canvas._tkcanvas.pack(side=Tk.RIGHT, fill=Tk.BOTH, expand=0)
def _load():
data = filedialog.askopenfilename(initialdir = "/", title = "Select file", filetypes = (("nii files","*.nii"),("gz files", "*.gz"),("all files","*.*")))
data_load = load_nii(data)
data_read = read_img_data(data_load)
data_read = np.asanyarray(data_read)
OrthoSlicer3D(data_read, axes=axes).show()
coords = []
def _onclick(event):
coords.append((event.xdata, event.ydata, event.zdata))
return coords
canvas.mpl_connect('button_press_event', _onclick)
buttonLoad = Tk.Button(master=root, text='Load', command=_load)
buttonLoad.pack(side=Tk.LEFT, expand = 1)
Tk.mainloop()
But the traceback is:
Traceback (most recent call last):
File "C:\Users\migue\Documents\IM\TFG\venv\lib\site-packages\matplotlib\cbook\__init__.py", line 388, in process
proxy(*args, **kwargs)
File "C:\Users\migue\Documents\IM\TFG\venv\lib\site-packages\matplotlib\cbook\__init__.py", line 228, in __call__
return mtd(*args, **kwargs)
File "C:/Users/migue/Documents/IM/TFG/pruebsd.py", line 58, in _onclick
coords.append((event.xdata, event.ydata, event.zdata))
AttributeError: 'MouseEvent' object has no attribute 'zdata'

Resources