I cannot get pyplot to produce "cropped" images, that is, get rid of the grey left and right borders, as it is, it is not an accurate representation of the sound waveform : This sound file has no silence before and after.
My code :
import gtk
from matplotlib.figure import Figure
from numpy import arange, sin, pi
import scipy.io.wavfile as wavfile
from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas
win = gtk.Window()
win.connect("destroy", lambda x: gtk.main_quit())
win.set_default_size(400,300)
win.set_title("Cropping figure")
rate, data = wavfile.read(open('/home/px/gare_du_nord-catchlak.wav', 'r'))
f = Figure()
a = f.add_subplot(111, axisbg=(0.1843, 0.3098, 0.3098))
a.plot(range(len(data)),data, color="OrangeRed", linewidth=0.5, linestyle="-")
a.axis('off')
a.autoscale_view('tight')
canvas = FigureCanvas(f) # a gtk.DrawingArea
win.add(canvas)
win.show_all()
gtk.main()
OK, I got my answer :
f.subplots_adjust(0, 0, 1, 1)
EDIT:
This also works, in fact it works even better:
a.margins(0, 0)
Related
The following code display the image and audio in the top-bottom style:
Here is the test code:
import librosa
import matplotlib.pyplot as plt
import IPython.display as ipd
def plot_it(name, audio, sample_rate):
plt.figure(figsize=(8, 1))
plt.plot(audio)
plt.gca().set_title(name)
plt.show()
ipd.display(ipd.Audio(data=audio, rate=sample_rate))
Is it possible for changing the "top-bottom" style to "left-right" style for displaying the audio at the right side of the plt figure?
You can use a GridspecLayout which is similar to matplotlib's GridSpec. In order to direct to output into the needed grid cells, you can capture it using the Output widget:
import librosa
import matplotlib.pyplot as plt
import IPython.display as ipd
from ipywidgets import Output, GridspecLayout
def plot_it(name, audio, sample_rate):
grid = GridspecLayout(1, 2, align_items='center')
out = Output()
with out:
fig, ax = plt.subplots(figsize=(8, 1))
ax.plot(audio)
ax.set_title(name)
plt.close(fig)
ipd.display(ax.figure)
grid[0, 0] = out
out = Output()
with out:
ipd.display(ipd.Audio(data=audio, rate=sample_rate))
grid[0, 1] = out
ipd.display(grid)
name = 'nutcracker'
filename = librosa.example(name)
y, sr = librosa.load(filename)
plot_it(name, y, sr)
(It is essential to close the figure, otherwise you'll have double output of the figure. This is easier to do this using the OOP than the pyplot interface, that's why I changed your matplotlib code a bit)
How to fix BarGraphItem height when zoom in or zoom out pyqtgraph plot, it should be similar with axis font, the font size is in pixel, please someone helps, thank you very much, basic code as below:
import numpy as np
import pyqtgraph as pg
pg.setConfigOption('leftButtonPan', False)
win = pg.plot()
win.setWindowTitle('pyqtgraph example: BarGraphItem')
x = np.arange(10)
bg1 = pg.BarGraphItem(x=x, height=5, width=1,brush='r')
win.addItem(bg1)
win.setYRange(0,110)
win.setLimits(yMin=0,yMax=110,xMin=-0.5,xMax=11)
if name == 'main':
pg.exec()
I expect to hover my mouse over the plot and get clean data reading on the right side of the navigation bar in the automatically-generated plot window.
In my case (see code at the bottom), however, if I turn the y-axis tick labels into decibel, the y-reading in the navigation bar (bottom right corner) will disappear, like this:
Workaround: If you comment out the #PROBLEM code block in the code below, then the y-reading in the bottom right corner will be visible, like this:
The code I used to pack the widgets:
from os.path import abspath, dirname, join
import tkinter as tk
import numpy as np
import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk as NavigationToolbar
from scipy.io import wavfile
root = tk.Tk()
mainframe = tk.Frame(root)
mainframe.pack()
frame = tk.Frame(mainframe)
frame.pack()
figFrame = tk.Frame(frame)
toolFrame = tk.Frame(frame)
figFrame.pack(side='top', fill='both', expand=True)
toolFrame.pack(side='top', fill='both', expand=True)
# Place the figure
fig = plt.Figure()
figWidget = FigureCanvasTkAgg(fig, master=figFrame)
track = figWidget.get_tk_widget()
track.pack(side='top', fill='both', expand=True)
# Place the toolbar
toolbar = NavigationToolbar(figWidget, toolFrame)
toolbar.pack(side='top', fill='both', expand=True)
# Get data
SR, signal = wavfile.read(join(abspath(dirname(__file__)), 'y.wav'))
# Plot the signal read from wav file
ax = fig.add_subplot(111)
ax.set_title('Waveform and Spectrogram of a wav file')
ax.plot(signal)
ax.set_xlabel('Sample')
ax.set_ylabel('Amplitude')
# PROBLEM: Truncated y-readings in Toolbar
ax.set_ylabel('Amplitude (dB)')
ticks = ax.get_yticks()
t1 = 20*np.log10(-ticks[(ticks < 0)])
t2 = 20*np.log10(ticks[(ticks > 0)])
t1 = [float('{:.1f}'.format(i)) for i in t1]
t2 = [float('{:.1f}'.format(i)) for i in t2]
ticks = np.concatenate((t1, [-np.inf], t2))
ax.set_yticklabels(ticks)
# PROBLEM: END
plt.show()
root.mainloop()
I wonder where I did wrong. My guess is that when the ticks are hacked (my way), then there will be no reading at all.... If so, then that's a pity, because I only modified the ticks not the data.
It's clear that no useful y coordinate can be shown when you set the ticklabels manually; maybe that becomes clearer if you consider that you could have labelled the plot with "Apple", "Banana", "Cherry" - in that case what would the coordinate be when the mouse is halfway between "Banana" and "Cherry"?
You may however use a FuncFormatter to set the format of the tickslabels.
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
import numpy as np
signal = np.sin(np.linspace(0,12,300))*.7
fig, ax = plt.subplots()
ax.set_title('Waveform and Spectrogram of a wav file')
ax.plot(signal)
ax.set_xlabel('Sample')
ax.set_ylabel('Amplitude (dB)')
def fmt(x,pos=None):
if x==0:
return "-inf"
else:
return '{:.1f}'.format(20*np.log10(np.sign(x)*x))
ax.yaxis.set_major_formatter(FuncFormatter(fmt))
plt.show()
The following code I am working on in not behaving the way I wish it to. I have embedded a matplotlib graph into a tkinter canvas. The program opens up two windows, one of which functions properly, and one of which is not necessary.I am not sure how to fix this. Here is the code, please ignore the unnecessary imports :)
import numpy as np
import sys
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib as mpl
from matplotlib import cm
from numpy.random import random
from matplotlib.widgets import Button
import matplotlib.colors
import tkinter as tk
import matplotlib.backends.tkagg as tkagg
from matplotlib.backends.backend_agg import FigureCanvasAgg
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
DEBUG_MODE = False #Debug mode - True = ON
MATRIX_WIDTH = 50
MATRIX_HEIGHT = 50
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
LED_COUNT = MATRIX_WIDTH * MATRIX_HEIGHT
REFRESH_RATE = 30 #REFRESH_RATE used to control FuncAnimation interval
MATRIX = random((50,50)) #Fills MATRIX as not to be null for first print
plt.rcParams['toolbar'] = 'None' #Disables matplotlib toolbar
fig = plt.figure(figsize=(3,3)) #'figsize' measured in inches
im = plt.imshow(MATRIX, interpolation='nearest', cmap=cm.Spectral)
plt.axis('off') #Turns off x, y axis
def data_gen(): #Generates amd populates MATRIX with pattern data
while True:
MATRIX = random((MATRIX_WIDTH, MATRIX_HEIGHT))
yield MATRIX
if (DEBUG_MODE): print("MATRIX yeilded")
def update(data): #Updates/prints new MATRIX from data_gen()
im.set_array(data)
if (DEBUG_MODE): print("Updated data")
root = tk.Tk()
label = tk.Label(root,text="Matrix Program").grid(column=0, row=0)
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().grid(column=0,row=1)
ani = animation.FuncAnimation(fig, update, data_gen, interval=REFRESH_RATE)
plt.show()
What needs to be done to this code so that it opens only one canvas from tkinter with the live matplotlib graph embedded?
How can I set the size of the canvas?
Do not call plt.show() if you want to show your figure inside a tk GUI. Best do not use pyplot at all when embedding.
On the other hand, you probably want to start the mainloop, tk.mainloop(), at some point.
Refer to the matplotlib example on how to embedd a matplotlib figure into tk.
I have tried running the example code on the SciPy website, but I get this error:
Traceback (most recent call last):
File ".\matplotlibPySide.py", line 24, in <module>
win.setCentralWidget(canvas)
TypeError: 'PySide.QtGui.QMainWindow.setCentralWidget' called with wrong argument types:
PySide.QtGui.QMainWindow.setCentralWidget(FigureCanvasQTAgg)
Supported signatures:
PySide.QtGui.QMainWindow.setCentralWidget(PySide.QtGui.QWidget)
I am building a simple scientific data logger that will eventually be used in commercial applications, so I really need both the LGPL from PySide and plotting functionality. Does anyone have experience on how to get this to work or alternative plotting packages or ideas?
Thanks in advance.
The example that you mention:
http://www.scipy.org/Cookbook/Matplotlib/PySide
works, but you might need to suggest the use of PySide:
...
matplotlib.use('Qt4Agg')
matplotlib.rcParams['backend.qt4']='PySide'
import pylab
...
I had similar goals (LGPL, potential commercial use) and here's how I ended up getting it to work.
Create a matplotlib widget (see here for a more detailed one for PyQt):
import matplotlib
matplotlib.use('Qt4Agg')
matplotlib.rcParams['backend.qt4']='PySide'
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
class MatplotlibWidget(FigureCanvas):
def __init__(self, parent=None,xlabel='x',ylabel='y',title='Title'):
super(MatplotlibWidget, self).__init__(Figure())
self.setParent(parent)
self.figure = Figure()
self.canvas = FigureCanvas(self.figure)
self.axes = self.figure.add_subplot(111)
self.axes.set_xlabel(xlabel)
self.axes.set_ylabel(ylabel)
self.axes.set_title(title)
In Qt Designer I created a blank widget to hold my plot and then when I __init__ the main window I call setupPlot:
def setupPlot(self):
# create a matplotlib widget
self.DataPlot = MatplotlibWidget()
# create a layout inside the blank widget and add the matplotlib widget
layout = QtGui.QVBoxLayout(self.ui.widget_PlotArea)
layout.addWidget(self.DataPlot,1)
Then I call plotDataPoints as needed:
def plotDataPoints(self,x,y):
self.DataPlot.axes.clear()
self.DataPlot.axes.plot(x,y,'bo-')
self.DataPlot.draw()
Note: this clears and redraws the entire plot every time (since the shape of my data keeps changing) and so isn't fast.
I think you may have posted this on the matplotlib mailing list. But just in case someone else is looking for the answer. The best option is to use the master branch on Github, but if you can't or don't know how to work the Github version you can use the following code to render a plot in PySide.
import numpy as np
from matplotlib import use
use('AGG')
from matplotlib.transforms import Bbox
from matplotlib.path import Path
from matplotlib.patches import Rectangle
from matplotlib.pylab import *
from PySide import QtCore,QtGui
rect = Rectangle((-1, -1), 2, 2, facecolor="#aaaaaa")
gca().add_patch(rect)
bbox = Bbox.from_bounds(-1, -1, 2, 2)
for i in range(12):
vertices = (np.random.random((4, 2)) - 0.5) * 6.0
vertices = np.ma.masked_array(vertices, [[False, False], [True, True], [False, False], [False, False]])
path = Path(vertices)
if path.intersects_bbox(bbox):
color = 'r'
else:
color = 'b'
plot(vertices[:,0], vertices[:,1], color=color)
app = QtGui.QApplication(sys.argv)
gcf().canvas.draw()
stringBuffer = gcf().canvas.buffer_rgba(0,0)
l, b, w, h = gcf().bbox.bounds
qImage = QtGui.QImage(stringBuffer,
w,
h,
QtGui.QImage.Format_ARGB32)
scene = QtGui.QGraphicsScene()
view = QtGui.QGraphicsView(scene)
pixmap = QtGui.QPixmap.fromImage(qImage)
pixmapItem = QtGui.QGraphicsPixmapItem(pixmap)
scene.addItem(pixmapItem)
view.show()
app.exec_()