Discretization of a diff. equation gives weird results - python

I have a code in Python that draws wave functions and energy for different potentials:
# -*- coding: cp1250 -*-
from math import *
from scipy.special import *
from pylab import *
from scipy.linalg import *
firebrick=(178./255.,34./255.,34./255.)
indianred=(176./255.,23./255.,31./255.)
steelblue=(70./255.,130./255.,180./255.)
slategray1=(198./255.,226./255.,255./255.)
slategray4=(108./255.,123./255.,139./255.)
lavender=(230./255.,230./255.,230./255.)
cobalt=(61./255.,89./255.,171./255.)
midnightblue=(25./255.,25./255.,112./255.)
forestgreen=(34./255.,139./255.,34./255.)
#definiranje mreze
Nmesh=512
L=4.0
dx=L/Nmesh
Xmax=L
x=arange(-L,L+0.0001,dx)
Npts=len(x)
numwav=0 #redni broj valne funkcije koji se iscrtava
V=zeros([Npts],float)
for i in range(Npts):
V[i]=x[i]**50
a=zeros([2,Npts-2],float)
wave=zeros([Npts],float)
wave1=zeros([Npts],float)
encor=3.0/4*(3.0/4)**(1.0/3)
#numericko rjesenje
for i in range(1,Npts-1,1):
a[0,i-1]= 1.0/dx**2+V[i] #dijagonalni elementi
a[1,i-1]=-1.0/dx**2/2 #elementi ispod dijagonale
a[1,Npts-3]=-99.0 #element se ne koristi
eig,vec=eig_banded(a,lower=1) #rutina koja dijagonalizira tridijagonalnu matricu
for i in range(1,Npts-1,1):
wave[i]=vec[i-1,numwav]
wave[0]=0.0 #valna funkcija u prvoj tocki na mrezi ima vrijednost nula
wave[Npts-1]=0.0 #valna funkcija u zadnjoj tocki na mrezi ima vrijednost nula
for i in range(1,Npts-1,1):
wave1[i]=(2.0/pi*(3.0/4)**(1.0/3))**0.25*exp(-(3.0/4)**(1.0/3)*x[i]**2)
wave1[0]=0.0 #valna funkcija u prvoj tocki na mrezi ima vrijednost nula
#wave1[Npts-1]=0.0 #valna funkcija u zadnjoj tocki na mrezi ima vrijednost nula
#wave1=omjer*150*wave1+encor
wave=150*wave+eig[numwav]
#graf potencijala
line=plt.plot(x,V)
plt.setp(line,color='firebrick',linewidth=2)
#crtanje odabranog nivoa i odgovarajuce valne funkcije
plt.axhline(y=eig[numwav],linewidth=2,color='steelblue')
#plt.axhline(y=encor,linewidth=2,color='midnightblue')
#crtanje tocaka valne funkcije
plt.plot(x,wave,"b-",linewidth=2,color='forestgreen')
#plt.plot(x,wave1,"-",linewidth=2,color='indianred')
plt.xlabel(r'$x$',size=14)
plt.ylabel(r'$V(x)$',size=14)
plt.title(r'Valna funkcija i energija 3. pobuđenog stanja za $V(x)=x^{50}$')
plt.axis([-3.0,3.0,-8.0,100.0]) #raspon x i y osi
plt.grid(True)
plt.legend((r'$V(x)$',r'$E_0$',r'$\psi_0$'))
plt.show()
Ignore the ignored lines, they are not important for this case, and the language :D
Anyhow, I have a problem. If I draw the potentials (the V part), for let's say up to x^20 it draws nice, like this for x^6:
If I put the potential, say x^50 it becomes this:
So what seems to be the problem? Why is he making such big mistake? It should be smooth, and from the theory as I reach the point V(x)=x^p for very large p (p → ∞) the potential should go to the famous infinite square well, which looks like this:
So I'm suspecting that for bigger potentials I need more points to draw it in the given range. So should I just increase the number of the Nmesh (grid)? Since he says that the Npts=len(x) - the number of points he's taking. Am I right? That seems logical, but I want to be certain.
Thanks for any advice and help
EDIT: I tried expanding the Nmesh but at very large numbers I either get that grid is too big, or that there is memory problems.
If I take, say 2048 I get the same picture but just shifted a bit and narrower.

Use select argument for eig_banded():
#!/usr/bin/env python
from __future__ import division
import functools
import math
import sys
from timeit import default_timer as timer
import numpy as np
import matplotlib.pyplot as plt
import scipy.linalg as linalg
def report_time(func):
#functools.wraps(func)
def wrapper(*args, **kwargs):
start = timer()
try: return func(*args, **kwargs)
finally:
print '%s takes %.2f seconds' % (func.__name__, timer()-start)
return wrapper
#report_time
def calc(Nmesh,POWER,L ,numwav=0):
#
dx=L/Nmesh
x = np.arange(-L,L+0.0001,dx)
Npts=len(x)
V = x**POWER
#
ai = np.empty((2,Npts)) # ai[:,i] = a[:,i-1]
ai[0,:] = 1/dx**2 + V #
ai[1,:] = -1.0/dx**2/2 #
ai[1,Npts-2] = -99.0 #
a = ai[:,1:-1]
f = report_time(linalg.eig_banded)
eig, vec = f(a, lower=True,overwrite_a_band=True,
select='i',select_range=(0,numwav)
) #
wave = np.empty(Npts)
wave[1:-1] = vec[:,numwav]
wave[0] = 0 #
wave[Npts-1] = 0 #
wave = 150*wave + eig[numwav]
return x, V, wave, eig[numwav]
def main():
try: numwav = int(sys.argv[1])
except (IndexError, ValueError):
numwav = 0
POWER=100
L=4.0
Nmesh = 512
print 'Nmesh=%d' % Nmesh
x, V, wave, y = calc(Nmesh, POWER, L,numwav)
#
line = plt.plot(x,V)
plt.setp(line,color='firebrick',linewidth=2)
#
plt.plot(x,wave,"b-",linewidth=2,color='forestgreen')
#
plt.axhline(y=y,linewidth=2,color='steelblue')
plt.xlabel(r'$x$',size=14)
plt.ylabel(r'$V(x)$',size=14)
plt.title(r'$V(x)=x^{%d}$, ' % POWER)
plt.axis([-(abs(L)-1), abs(L)-1,min(min(wave), y, min(V))-1, max(max(wave), y)+1]) #
plt.grid(True)
plt.legend((r'$V(x)$',r'$E_%d$' % numwav,r'$\psi_%d$' % numwav))
plt.savefig('V_%d_%d_%d.png' % (Nmesh, POWER, numwav))
plt.show()
if __name__=="__main__":
main()
Output
Nmesh=512
eig_banded takes 0.01 seconds
calc takes 0.01 seconds
Here's a variant with numwav=4:

Related

How can I get the start and end indices of a note in a volume graph?

I am trying to make a program, that tells me when a note has been pressed.
I have the following notes exported as a .wav file (The C Major Scale 4 times with different rhythms, dynamics and in different octaves):
I can get the volumes of my sound file using the following code:
from scipy.io import wavfile
def get_volume(file):
sr, data = wavfile.read(file)
if data.ndim > 1:
data = data[:, 0]
return data
volumes = get_volume("FILE")
Here are some information about the output:
Max: 27851
Min: -25664
Mean: -0.7569383391943734
A Sample from the array: [ -7987 -8615 -8983 -9107 -9019 -8750 -8324 -7752 -7033 -6156
-5115 -3920 -2610 -1245 106 1377 2520 3515 4364 5077
5659 6113 6441 6639 6708 6662 6518 6288 5962 5525
4963 4265 3420 2418 1264 -27 -1429 -2901 -4388 -5814
-7101 -8186 -9028 -9614 -9955 -10077 -10012 -9785 -9401 -8846]
And here is what I get when I plot the volumes array (x is the index, y is the volume):
I want to get the indices of the start and end of the notes like the ones in the image (Did it by hand not accurate):
When I looked at the data I realized, that it is a 1d array and I also noticed, that when a note gets louder or quiter it is not smooth. It is like a ZigZag, but there is still a trend. So basically I can't just get the gradients (slope) of each point. So I though about grouping notes into batches and getting the average gradient there and thus doing the calculations with it, like so:
def get_average_gradient(arr):
# Calculates average gradient
return sum([i - (sum(arr) / len(arr)) for i in arr]) / len(arr)
def get_note_start_end(arr_size, batch_size, arr):
# Finds start and end indices
ranges = []
curr_range = [0]
prev_slope = curr_slope = "NO SLOPE"
has_ended = False
for i, j in enumerate(arr):
if j > 0:
curr_slope = "INCREASING"
elif j < 0:
curr_slope = "DECREASING"
else:
curr_slope = "NO SLOPE"
if prev_slope == "DECREASING" and not has_ended:
if i == len(arr) - 1 or arr[i + 1] < 0:
if curr_slope != "DECREASING":
curr_range.append((i + 1) * batch_size + batch_size)
ranges.append(curr_range)
curr_range = [(i + 1) * batch_size + batch_size + 1]
has_ended = True
if has_ended and curr_slope == "INCREASING":
has_ended = False
prev_slope = curr_slope
ranges[-1][-1] = arr_size - 1
return ranges
def get_notes(batch_size, arr):
# Gets the gradients of the batches
out = []
for i in range(0, len(arr), batch_size):
if i + batch_size > len(arr):
gradient = get_average_gradient(arr[i:])
else:
gradient = get_average_gradient(arr[i: i+batch_size])
# print(gradient, i)
out.append(gradient)
return get_note_start_end(len(arr), batch_size, out)
notes = get_notes(128, volumes)
The problem with this is, that if the batch size is too small, then it returns the indices of small peaks, which aren't a note on their own. If the batch size is too big then the program misses the start and end indices.
I also tried to get the notes, by using the silence.
Here is the code I used:
from pydub import AudioSegment, silence
audio = intro = AudioSegment.from_wav("C - Major - Test.wav")
dBFS = audio.dBFS
notes = silence.detect_nonsilent(audio, min_silence_len=50, silence_thresh=dBFS-10)
This worked the best, but it still wasn't good enough. Here is what I got:
It some notes pretty well, but it wasn't able to identify notes accurately if the notes themselves didn't become very quite before a different one was played (Like in the second scale and in the fourth scale).
I have been thinking about this problem for days and I have basically tried most if not all of the good(?) ideas I had. I am new to analysing audio files. Maybe I am using the wrong data to do what I want to do. Maybe I need to use the frequency data (I tried getting it, but couldn't make sense of it)
Frequency code:
from scipy.fft import *
from scipy.io import wavfile
import matplotlib.pyplot as plt
def get_freq(file, start_time, end_time):
sr, data = wavfile.read(file)
if data.ndim > 1:
data = data[:, 0]
else:
pass
# Fourier Transform
N = len(data)
yf = rfft(data)
xf = rfftfreq(N, 1 / sr)
return xf, yf
FILE = "C - Major - Test.wav"
plt.plot(*get_freq(FILE, 0, 10))
plt.show()
And the frequency graph:
And here is the .wav file:
https://drive.google.com/file/d/1CERH-eovu20uhGoV1_O3B2Ph-4-uXpiP/view?usp=sharing
Any help is appreciated :)
think this is what you need:
first you convert negative numbers into positive ones and smooth the line to eliminate noise, to find the lower peaks yo work with the negative values.
from scipy.io import wavfile
import matplotlib.pyplot as plt
from scipy.signal import find_peaks
import numpy as np
from scipy.signal import savgol_filter
def get_volume(file):
sr, data = wavfile.read(file)
if data.ndim > 1:
data = data[:, 0]
return data
v1 = abs(get_volume("test.wav"))
#Smooth the curve
volumes=savgol_filter(v1,10000 , 3)
lv=volumes*-1
#find peaks
peaks,_ = find_peaks(volumes,distance=8000,prominence=300)
lpeaks,_= find_peaks(lv,distance=8000,prominence=300)
# plot them
plt.plot(volumes)
plt.plot(peaks,volumes[peaks],"x")
plt.plot(lpeaks,volumes[lpeaks],"o")
plt.plot(np.zeros_like(volumes), "--", color="gray")
plt.show()
Plot with your test file, x marks the high peaks and o the lower peaks
This article presents two python libraries (Aubio, librosa) to achieve what you need and includes examples of how to use them: How to Use Python to Detect Music Onsets by Lynn Zheng

I defined both of my functions but it doesn't plot

Hi guys im trying to plot these two functions x(x2) vs y(x2). x(x2) being equal to log10(x_2) and y(x_2) being equal to gam(x2) which was then equal also equal to (gam0 - 0.0187 * temp * math.log10(1+628.1455.556x_2)). It seems like the code for y(x_2) works fine but i can't seem to get the code for x(x_2) to work. When it does plot it should look like this 1
import matplotlib.pyplot as plt
import numpy as np
import math
import pylab
%matplotlib inline
gam0 = 72.8
temp = 293.15
#x = range(0, 10000)
#x_2= range(0, 10000)
def gam(x_2):
returns = []
for x_i in x_2:
returns.append(gam0 - 0.0187 * temp * math.log10(1+628.14*55.556*x_i))
return returns
def x(x_2):
returns = math.log10(x_2)
x()
plt.plot(gam(x_2), x(x_2))
plt.xlabel('Log_10x_2')
plt.ylabel('gamma (erg cm^2)')
plt.show()
These are the errors im getting
NameError Traceback (most recent call last)
<ipython-input-13-ac6002d962a0> in <module>
25
26
---> 27 plt.plot(gam(x_2), x(x_2))
28
29 plt.xlabel('Log_10x_2')
<ipython-input-13-ac6002d962a0> in x(x_2)
19 return returns
20 def x(x_2):
---> 21 returns = numpy.log10(x_2)
22
23 return returns
I found a number of issues with your code:
Your function x(x_2) is not return anything. Instead it keeps calling itself recursively.
You are calling math.log10, which only acts on a single number, not an array. You can either wrap that in a loop, or call the numpy version.
In your function gam(x_2) you are using log10, but log is needed.
Your plot range is of, you need much smaller values on the x-axis.
I added two variants, because the spacing of the grid points is different on the linear and logarithmic scales. Also, with np.linspace() you can specify the number of grid points, instead of the step size. (For details see https://numpy.org/doc/1.18/reference/generated/numpy.linspace.html)
Here is the overall code
import matplotlib.pyplot as plt
import numpy as np
gam0 = 72.8
temp = 293.15
x_2 = np.linspace(1e-7, 1e-1, 1000) # evenly spaced on linear scale
x_2 = 10**np.linspace(-7, -1, 1000) # evenly spaced on logarithmic scale
def gam(x_2):
return gam0 - 0.0187 * temp * np.log(1+628.14*55.556*x_2)
def x(x_2):
return np.log10(x_2)
plt.plot(x(x_2), gam(x_2))
plt.xlabel('Log_10x_2')
plt.ylabel('gamma (erg cm^2)')
It is also possible, to let matplotlib deal with the log scale on the x-axis:
plt.plot(x_2, gam(x_2))
plt.xlabel('x_2')
plt.ylabel('gamma (erg cm^2)')
plt.gca().set_xscale('log')

Trying to run aMD simulation using ase, keep getting this error-ValueError: shapes (0,) and (3,3) not aligned: 0 (dim 0) != 3 (dim 0)

This is my python code. I must use embedded atom potential for my cluster. My structure that I imported is a bimetallic nanocluster of 1013 atoms. I need to run MD at fixed temperature of 3000 K. The simulation starts at 0 and jumps to 53573K then to 50656K before giving the error message.
from ase.md.langevin import Langevin
from ase.io.trajectory import Trajectory
from ase import units
import numpy as np
from ase import Atoms
from ase.calculators.eam import EAM
from ase.io import write, read
# Kelvin (Set up the temperature)
T = 3000
#Import the global minimum structure
fName= 'globalminstr.xyz'
#Interatomic Potential
atoms = read(fName)
calc= EAM(potential='Zope-Ti-Al-2003.eam.alloy')
atoms.set_calculator(calc)
#Langevin dynamics
dyn = Langevin(atoms, 5 * units.fs, T * units.kB, 0.002)
def printenergy(a=atoms): # store a reference to atoms in the definition.
"""Function to print the potential, kinetic and total energy."""
epot = a.get_potential_energy() / len(a)
ekin = a.get_kinetic_energy() / len(a)
print('Energy per atom: Epot = %.3feV Ekin = %.3feV (T=%3.0fK) '
'Etot = %.3feV' % (epot, ekin, ekin / (1.5 * units.kB), epot + ekin))
dyn.attach(printenergy, interval=50)
# Saving the positions of all atoms after every 100th time step.
traj = Trajectory('moldyn.traj', 'w', atoms)
dyn.attach(traj.write, interval=50)
# Running dynamics
printenergy()
dyn.run(5000)

Importing Modules within Scripts in Python Class

I'm having two issues with attempting to define my own class. First, the most basic issue is that if I write a python script and try to import it into a second script, the import fails (the scripts are in the same directory). For example, I wrote a script called first.py:
def foo(): print("foo")
If I try to import this into a second script, I get 'no module found'
import first
first.foo()
ImportError: No module named first
Second, I wrote a script that defines a class for non-linear regression. The script imports the modules within the class. However, I'm also required to import the modules OUTSIDE of the class as well. The script won't work if the modules aren't imported both inside and outside of the class definition:
class NLS:
''' This provides a wrapper for scipy.optimize.leastsq to get the relevant output for nonlinear least squares.
Although scipy provides curve_fit for that reason, curve_fit only returns parameter estimates and covariances.
This wrapper returns numerous statistics and diagnostics'''
# IMPORT THE MODULES THE FIRST TIME - WILL NOT RUN WITHOUT THESE
import numpy as np
from scipy.optimize import leastsq
import scipy.stats as spst
def __init__(self, func, p0, xdata, ydata):
# Check the data
if len(xdata) != len(ydata):
msg = 'The number of observations does not match the number of rows for the predictors'
raise ValueError(msg)
# Check parameter estimates
if type(p0) != dict:
msg = "Initial parameter estimates (p0) must be a dictionry of form p0={'a':1, 'b':2, etc}"
raise ValueError(msg)
self.func = func
self.inits = p0.values()
self.xdata = xdata
self.ydata = ydata
self.nobs = len( ydata )
self.nparm= len( self.inits )
self.parmNames = p0.keys()
for i in range( len(self.parmNames) ):
if len(self.parmNames[i]) > 5:
self.parmNames[i] = self.parmNames[i][0:4]
# Run the model
self.mod1 = leastsq(self.func, self.inits, args = (self.xdata, self.ydata), full_output=1)
# Get the parameters
self.parmEsts = np.round( self.mod1[0], 4 )
# Get the Error variance and standard deviation
self.RSS = np.sum( self.mod1[2]['fvec']**2 )
self.df = self.nobs - self.nparm
self.MSE = self.RSS / self.df
self.RMSE = np.sqrt( self.MSE )
# Get the covariance matrix
self.cov = self.MSE * self.mod1[1]
# Get parameter standard errors
self.parmSE = np.diag( np.sqrt( self.cov ) )
# Calculate the t-values
self.tvals = self.parmEsts/self.parmSE
# Get p-values
self.pvals = (1 - spst.t.cdf( np.abs(self.tvals), self.df))*2
# Get biased variance (MLE) and calculate log-likehood
self.s2b = self.RSS / self.nobs
self.logLik = -self.nobs/2 * np.log(2*np.pi) - self.nobs/2 * np.log(self.s2b) - 1/(2*self.s2b) * self.RSS
del(self.mod1)
del(self.s2b)
del(self.inits)
# Get AIC. Add 1 to the df to account for estimation of standard error
def AIC(self, k=2):
return -2*self.logLik + k*(self.nparm + 1)
del(np)
del(leastsq)
# Print the summary
def summary(self):
print
print 'Non-linear least squares'
print 'Model: ' + self.func.func_name
print 'Parameters:'
print " Estimate Std. Error t-value P(>|t|)"
for i in range( len(self.parmNames) ):
print "% -5s % 5.4f % 5.4f % 5.4f % 5.4f" % tuple( [self.parmNames[i], self.parmEsts[i], self.parmSE[i], self.tvals[i], self.pvals[i]] )
print
print 'Residual Standard Error: % 5.4f' % self.RMSE
print 'Df: %i' % self.df
## EXAMPLE USAGE
import pandas as pd
# IMPORT THE MODULES A SECOND TIME. WILL NOT RUN WITHOUT THESE
import numpy as np
from scipy.optimize import leastsq
import scipy.stats as spst
# Import data into dataframe
respData = pd.read_csv('/Users/Nate/Documents/FIU/Research/MTE_Urchins/Data/respiration.csv')
# Standardize to 24 h
respData['respDaily'] = respData['C_Resp_Mass'] * 24
# Create the Arrhenius temperature
respData['Ar'] = -1 / (8.617 * 10**-5 * (respData['Temp']+273))
# Define the likelihood null model
def nullMod(params, mass, yObs):
a = params[0]
c = params[1]
yHat = a*mass**c
err = yObs - yHat
return(err)
p0 = {'a':1, 'b':1}
tMod = NLS(nullMod, p0, respData['UrchinMass'], respData['respDaily'] )
tMod.summary()
tMod.AIC()
tMod.logLik
These problems are related because I try to import this class into another script and I can't (as in the first problem). Can anyone tell me what's going on?
Update
I just started being able to import scripts. Whatever that funky clean on start path was appears to have finally been deleted somehow. No idea what that was. However, I still don't understand why, if I import the necessary modules in my class definition, I MUST import them in my other scripts as well. It seems to me that if my class imports the modules, I shouldn't need to import them globally as well. Is this correct?
I think the first comment from zhangxaochen is the best starting place for problem number number 1. sys.path should contain all the paths that python is searching for when you try to import a module. These are the steps I'd go through to solve this one:
Make sure os.getcwd() returns the same directory as os.path.dirname(sys.argv[0])
Next I'd make sure that that path is in sys.path list.
If both those check out....

Plot really big file in python (5GB) with x axis offset

I am trying to plot a very big file (~5 GB) using python and matplotlib. I am able to load the whole file in memory (the total available in the machine is 16 GB) but when I plot it using simple imshow I get a segmentation fault. This is most probable to the ulimit which I have set to 15000 but I cannot set higher. I have come to the conclusion that I need to plot my array in batches and therefore made a simple code to do that. My main isue is that when I plot a batch of the big array the x coordinates start always from 0 and there is no way I can overlay the images to create a final big one. If you have any suggestion please let me know. Also I am not able to install new packages like "Image" on this machine due to administrative rights. Here is a sample of the code that reads the first 12 lines of my array and make 3 plots.
import os
import sys
import scipy
import numpy as np
import pylab as pl
import matplotlib as mpl
import matplotlib.cm as cm
from optparse import OptionParser
from scipy import fftpack
from scipy.fftpack import *
from cmath import *
from pylab import *
import pp
import fileinput
import matplotlib.pylab as plt
import pickle
def readalllines(file1,rows,freqs):
file = open(file1,'r')
sizer = int(rows*freqs)
i = 0
q = np.zeros(sizer,'float')
for i in range(rows*freqs):
s =file.readline()
s = s.split()
#print s[4],q[i]
q[i] = float(s[4])
if i%262144 == 0:
print '\r ',int(i*100.0/(337*262144)),' percent complete',
i += 1
file.close()
return q
parser = OptionParser()
parser.add_option('-f',dest="filename",help="Read dynamic spectrum from FILE",metavar="FILE")
parser.add_option('-t',dest="dtime",help="The time integration used in seconds, default 10",default=10)
parser.add_option('-n',dest="dfreq",help="The bandwidth of each frequency channel in Hz",default=11.92092896)
parser.add_option('-w',dest="reduce",help="The chuncker divider in frequency channels, integer default 16",default=16)
(opts,args) = parser.parse_args()
rows=12
freqs = 262144
file1 = opts.filename
s = readalllines(file1,rows,freqs)
s = np.reshape(s,(rows,freqs))
s = s.T
print s.shape
#raw_input()
#s_shift = scipy.fftpack.fftshift(s)
#fig = plt.figure()
#fig.patch.set_alpha(0.0)
#axes = plt.axes()
#axes.patch.set_alpha(0.0)
###plt.ylim(0,8)
plt.ion()
i = 0
for o in range(0,rows,4):
fig = plt.figure()
#plt.clf()
plt.imshow(s[:,o:o+4],interpolation='nearest',aspect='auto', cmap=cm.gray_r, origin='lower')
if o == 0:
axis([0,rows,0,freqs])
fdf, fdff = xticks()
print fdf
xticks(fdf+o)
print xticks()
#axis([o,o+4,0,freqs])
plt.draw()
#w, h = fig.canvas.get_width_height()
#buf = np.fromstring(fig.canvas.tostring_argb(), dtype=np.uint8)
#buf.shape = (w,h,4)
#buf = np.rol(buf, 3, axis=2)
#w,h,_ = buf.shape
#img = Image.fromstring("RGBA", (w,h),buf.tostring())
#if prev:
# prev.paste(img)
# del prev
#prev = img
i += 1
pl.colorbar()
pl.show()
If you plot any array with more than ~2k pixels across something in your graphics chain will down sample the image in some way to display it on your monitor. I would recommend down sampling in a controlled way, something like
data = convert_raw_data_to_fft(args) # make sure data is row major
def ds_decimate(row,step = 100):
return row[::step]
def ds_sum(row,step):
return np.sum(row[:step*(len(row)//step)].reshape(-1,step),1)
# as per suggestion from tom10 in comments
def ds_max(row,step):
return np.max(row[:step*(len(row)//step)].reshape(-1,step),1)
data_plotable = [ds_sum(d) for d in data] # plug in which ever function you want
or interpolation.
Matplotlib is pretty memory-inefficient when plotting images. It creates several full-resolution intermediate arrays, which is probably why your program is crashing.
One solution is to downsample the image before feeding it into matplotlib, as #tcaswell suggests.
I also wrote some wrapper code to do this downsampling automatically, based on your screen resolution. It's at https://github.com/ChrisBeaumont/mpl-modest-image, if it's useful. It also has the advantage that the image is resampled on the fly, so you can still pan and zoom without sacrificing resolution where you need it.
I think you're just missing the extent=(left, right, bottom, top) keyword argument in plt.imshow.
x = np.random.randn(2, 10)
y = np.ones((4, 10))
x[0] = 0 # To make it clear which side is up, etc
y[0] = -1
plt.imshow(x, extent=(0, 10, 0, 2))
plt.imshow(y, extent=(0, 10, 2, 6))
# This is necessary, else the plot gets scaled and only shows the last array
plt.ylim(0, 6)
plt.colorbar()
plt.show()

Categories