Python - optimizing plot code - python

I am working on a live plot.I am getting data from a spectrum analyser which gives me the value at a certain frequency. But the program becomes slower the longer it runs.
So I hope you have some ideas. I also looked at my activity monitor while running and the RAM isn't full at all.
I tried to comment out ctf = ax.contourf( a, b, B, cmap=cma) which is responsible for plotting and if it don't need to draw it is so fast. But I need the plot so not drawing is not a solution at all.
And ax = plt.subplot( 111, polar = True) for extra information.
Here is my code:
while True :
trace = inst.query(':TRACe:DATA? TRACE1').partition(' ')[2][:-2].split(', ')# the first & last 2 entries are cut off, are random numbers
for value in trace : #write to file
f.write(value)
f.write('\n')
try : #looking if data is alright
trace = np.array(trace, np.float)
except ValueError: #if a ValueError is raised this message is displayed but the loop won't break and the piece is plotted in one color (green)
print'Some wrong data at the', i+1, 'th measurement'
longzeroarray = np.zeros(801)
a = np.linspace(i*np.pi/8-np.pi/16, i*np.pi/8+np.pi/16, 2)#Angle, circle is divided into 16 pieces
b = np.linspace(start -scaleplot, stop,801) #points of the frequency + 200 more points to gain the inner circle
A, B = np.meshgrid(a, longzeroarray)
cma = ListedColormap(['w'])
#actual plotting
ctf = ax.contourf( a, b, B, cmap=cma)
xCooPoint = i*np.pi/8 + np.pi/16 #shows the user the position of the plot
yCooPoint = stop
ax.plot(xCooPoint, yCooPoint, 'or', markersize = 15)
xCooWhitePoint = (i-1) * np.pi/8 + np.pi/16 #this erases the old red points
yCooWhitePoint = stop
ax.plot(xCooWhitePoint, yCooWhitePoint, 'ow', markersize = 15)
plt.draw()
time.sleep(60) #delaying the time to give analyser time to give us new correct data in the next step
i +=1
continue
maximasearch(trace,searchrange)
trace = np.insert(trace,0,zeroarray)
a = np.linspace(i*np.pi/8+np.pi/16-np.pi/8, i*np.pi/8+np.pi/16, 2)#Angle, circle is divided into 16 pieces
b = np.linspace(start -scaleplot, stop,801) #points of the frequency + 200 more points to gain the inner circle
A, B = np.meshgrid(a, trace)
#actual plotting
ctf = ax.contourf(a, b, B, cmap=cm.jet, vmin=-100, vmax=100)
xCooPoint = i*np.pi/8 + np.pi/16 #shows the user the position of the plot
yCooPoint = stop
ax.plot(xCooPoint, yCooPoint, 'or', markersize = 15)
xCooWhitePoint = (i-1) * np.pi/8 + np.pi/16 #this erases the old red points
yCooWhitePoint = stop
ax.plot(xCooWhitePoint, yCooWhitePoint, 'ow', markersize = 15)
plt.draw()
i+=1
Thats how the plot looks like, and with every new step a new piece of the circle is drawn.
EDIT
I found following question here on stack overflow: real-time plotting in while loop with matplotlib
I think the answer with 22 Upvotes could be helpful. Has anyone ever used blit ? I have no idea yet how to combine it with my code.
http://wiki.scipy.org/Cookbook/Matplotlib/Animations

I want to answer my own question again.
The best way to optimize the code is to calculate with modulo 2*pi for the radial values.
I changed my code a bit :
a = np.linspace((i*np.pi/8+np.pi/16-np.pi/8)%(np.pi*2), (i*np.pi/8+np.pi/16)%(np.pi*2), 2)
The problem before was that Python also plotted all the old pieces, because obviously the were still there but only under a layer of newly plotted data pieces. So although you didn't see the old plotted data, it was still drawn. Now only the circle from 0 to 2pi is redrawn.

Related

Matplotlib not plotting at all correctly, not seen anyone else have this issue

So, I'm trying to code with matplotlib, so that it plots coordinates of the majority of cities in the USA on a graph. As should be evident by the fact I'm asking this question, it isn't working. The code is just plotting all the points on a single diagonal line, shown below, and both axises are completely out of order (you can see it clearly on the y-axis). Below is both an image of the result, and the matplotlib code I'm using:
Image of multiple points on a single diagonal line with no order to either axises
Code:
def demand(places, distfact):
demandList = []
fig = plt.figure()
print(len(places))
for origin in places:
for destination in places:
if origin != destination:
dist = haversine(float(origin.lat), float(origin.lon), float(destination.lat),
float(destination.lon))
result = (int(origin.population) * int(destination.population)) / (dist * distfact)
line1 = [origin.name, destination.name, result,
[origin.lat, origin.lon], [destination.lat, destination.lon]]
line2 = [destination.name, origin.name, result,
[destination.lat, destination.lon], [origin.lat, origin.lon]]
if line2 not in demandList and result >= 75000000 and dist >= 30.0:
demandList.append(line1)
demandList.sort(key=lambda row: (row[2]), reverse=True)
for i in range(0, 20):
print(demandList[i][0], "->", demandList[i][1], ":", "{:,}".format(demandList[i][2]))
print("\n")
print(len(demandList) - 30, "routes")
print("\n")
for i in range(0,10):
ind = len(demandList) - i - 1
print(demandList[ind][0], "->", demandList[ind][1], ":", "{:,}".format(demandList[ind][2]))
for i in range(len(demandList)):
xpoints = np.array([demandList[i][3][0], demandList[i][4][0]])
ypoints = np.array([demandList[i][3][1], demandList[i][4][1]])
plt.plot(xpoints, ypoints, "o")
"places" is a list of objects. Each object contains a townID, name, population, latitude and longtitude. distfact is simply a number, in this example it's set to 5.
Just a guess as I can't see what's in your variables: try casting the values from your x_points and y_points variables to whatever makes sense in your case be it float or int. It seems to me that they are seen as strings by pyplot.
edit: Not a guess anymore, you're missing casts to float, when populating line1 with latitudes and longitudes. You do do it in your haversine computations but not three lines below.

"Button_Press_Event" Coordinates Being Called Before I Actually Click

I am plotting a fits image of a field of stars. I am then displaying circular apertures across the image on sufficiently bright stars. Next, I am trying to click on the star that I am interested in, and getting the brightness measurement out of the nearest circle. Finally, I want to use that brightness measurement for other calculations.
My problem is that the variable I declare to store the x,y coordinates of my click ("coords") seems to be getting called before I actually click, resulting in an empty array and errors.
A co-worker sent it to me many months ago, and once upon a time it worked flawlessly. But it seems that it's stopped working. It may be a result of updating some libraries/modules, but I can't be sure.
I have tried various combinations, including declaring "coords" in other function, in other locations, etc. I have tried changing the order of certain lines to perhaps get "coords" to be called later. I've also tried writing the code from the ground up, and have had many of the same errors. Because this specific code once worked, I attach it instead of my attempts.
To be honest, I don't fully understand the code, as I didn't write it. As a result, I don't understand what is being called when, or what any changes I've made actually do.
def plot_image(file, vmin=5, vmax=99, threshold=5, radius=25):
hdu=fits.open(file)
image = hdu[0].data
exptime = hdu[0].header['EXPTIME']
band = hdu[0].header['FILTERS']
airmass = hdu[0].header['AIRMASS']
readnoise = hdu[0].header['RN_01']
gain = hdu[0].header['GAIN_01']
obj = hdu[0].header['OBJECT']
sub = image[1500:2000,1500:2000]
bkg_sigma = mad_std(sub)
mean, median, std = sigma_clipped_stats(sub, sigma=3.0, maxiters=5)
daofind = photutils.DAOStarFinder(fwhm=2., threshold=threshold*bkg_sigma)
sources = daofind(sub - median)
positions = (sources['xcentroid'], sources['ycentroid'])
apertures = photutils.CircularAperture(positions, r=radius)
phot_table = photutils.aperture_photometry(sub - median, apertures)
pix = select(image, apertures)
print(pix)
if len(pix) == 2 or len(coords) == 2:
distance = np.sqrt((np.array(phot_table['xcenter'])-pix[0])**2 + (np.array(phot_table['ycenter'])-pix[1])**2)
star = np.argmin(dist)
counts = phot_table[star]['aperture_sum']
fluxfile = open('testfile.txt')
signal = (counts * gain) / exptime
err = np.sqrt(counts*gain + (readnoise**2*np.pi*radius**2))
else:
print('Pix length = 0')
def select(image, apertures, vmin = 5, vmax = 99):
global coords
coords = []
fig = plt.figure(figsize = (9,9))
ax = fig.add_subplot(111)
ax.imshow(image, cmap = 'gist_gray_r', origin='lower', vmin = np.percentile(image, vmin), vmax = np.percentile(image, vmax), interpolation='none')
apertures.plot(color='blue', lw=1.5, alpha=0.5, ax = ax)
ax.set_title('Hello')#label='Object: '+obj+'\nFilter: '+band)
cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()
fig.canvas.mpl_disconnect(cid)
if None in coords:
return [np.nan,np.nan]
else:
return np.round(coords)
def onclick(event):
x = event.xdata
y = event.ydata
global coords
coords = [x, y]
plt.close()
return
def closeonclick(event):
print('Close On Click')
plt.close()
return
Expected Result: The image is displayed with blue apertures overlaid. Then, I click on the desired star and the coordinates I click are stored to "coords" and printed to the console. The window displaying the image is closed alongside the previous step, as well. Finally, using those coordinates, it finds the nearest aperture and does some science with the resulting brightness.
Actual Result: "coords" is immediately printed (an empty list). Immediately after, the image is displayed. Clicking it does nothing. It doesn't change the value of "coords", nothing else is printed, nor does the window close.
I'll come back and delete this if it isn't right (I'd comment if I had the reputation), but it looks like you have to define a global variable outside any functions first, then use the keyword before the variable name inside a function to change its scope. Try moving "coords = []" outside your functions (the list will no longer be empty after the first call to "onclick", but each new click should replace the coordinates so it shouldn't be an issue).
Ref: https://www.programiz.com/python-programming/global-keyword

Plotting multiple graphs does not work using pylab

I want to visualize the Birthday Problem with different n. My aim is to plot multiple graphs in the same figure but it does not work. It only plots the last graph and ignores the others. I am using the Jupyter Notebook.
This is my Code:
from decimal import Decimal
def calc_p_distinct(n):
p_distinct = numpy.arange(0, n.size, dtype=Decimal)
for i in n:
p_distinct[i] = Decimal(1.0)
for i in n:
for person in range(i):
p_distinct[i] = Decimal(p_distinct[i]) * Decimal(((Decimal(365-person))/Decimal(365)))
return p_distinct
# n is the number of people
n = numpy.arange(0, 20)
n2 = numpy.arange(0, 50)
n3 = numpy.arange(0, 100)
# plot the probability distribution
p_distinct = calc_p_distinct(n)
pylab.plot(n, p_distinct, 'r')
p_distinct2 = calc_p_distinct(n2)
pylab.plot(n2, p_distinct2, 'g')
p_distinct3 = calc_p_distinct(n3)
pylab.plot(n3, p_distinct3, 'b')
# set the labels of the axis and title
pylab.xlabel("n", fontsize=18)
pylab.ylabel("probability", fontsize=18)
pylab.title("birthday problem", fontsize=20)
# show grid
pylab.grid(True)
# show the plot
pylab.show()
When I replace one of the calc_p_distinct() function calls with another built-in function (e.g. numpy.sin(n)), it will show me two graphs. So, I conclude that it must have something to do with my function. What am I doing wrong here?
This isn't a problem with matplotlib; all the lines are there, just on top of each other (which makes perfect sense; for 100 people, the probability for only the first 20 is the same as for a group of just 20 people).
If I quickly plot them with a different line width:

Plot sparsely populated 2d numpy array

from an iterative image pattern search with decreasing step size I have a 'quality' array. Due to the nature of the search pattern the array is not fully filled. In the first iteration I go with stepsize 10, find the best spot and there search a +-10 XY range to find the true best spot. So most of the array has every 10th slot filled and there is the small 'best' region that is densely filled. Now I want to plot this array and would want the plot to be 'interpolated' where needed by using the data every 10th slot. Now to do my search I initialize the array with a huge value. All my measurements are smaller and later I use the np.argmin(q) function. That works fine for searching but for plotting it is bad. The dynamic range of the plot is lost.
Here is an example from an older version of the code that does exhaustive but unnecessarily long search :
And here is what I get with the optimized search :
Here is the piece of code that does the plots. (q is the quality array to plot)
fig= plt.figure(1)
im= plt.imshow(q[::-1], cmap='rainbow', interpolation='none', extent=[-search_size,search_size,-search_size,search_size])
fig.savefig(pfn(img_fn), bbox_inches='tight')
The issue may point back to the initialization of the array. Again as I do a minimum search I do this :
q = np.empty(shape=(2*search_size,2*search_size))
q.fill(+1e20)
q_min = 1e20
for xs in range(-search_size,+search_size,search_step):
for ys in range(-search_size,+search_size,search_step):
img_shift = np.zeros_like(img)
img_shift[mom(ys):non(ys), mom(xs):non(xs)] = img[mom(-ys):non(-ys), mom(-xs):non(-xs)]
d = np.absolute(img_shift - prev_img)[search_size:-search_size,search_size:-search_size]
q[ys+search_size,xs+search_size] = np.sum(d)
if q[ys+search_size,xs+search_size] < q_min : q_min= q[ys+search_size,xs+search_size]
#print '1st iter try : %+3d %+3d %6.3f %6.3f' % ( xs, ys, q[ys+search_size,xs+search_size], q_min)
idxmin = np.argmin(q)
dy,dx = np.unravel_index(idxmin, q.shape)
dx= dx-search_size
dy= dy-search_size
print '1st iter best : dx= %+3d dy= %+3d' % ( dx , dy )
Then follows another loop with search_step = 1.
Is it possible to initialize the array i.e. with NaN ? Would that allow the minimum search? And/or would it allow the plotter to jump accross undefined entries?
So what's the best way to initialize / plot so that the search works and the plots look good?
Thanks,
Gert
Update #Nix G-D
The averaging fails. I first tried code following the recommendation.
q_int = pd.DataFrame(q).interpolate(method='linear', axis=0).values
fig= plt.figure(1)
im= plt.imshow(q_int[::-1], cmap='rainbow', interpolation='none', extent=[-search_size,search_size,-search_size,search_size])
However the 2D interpolation failed. (at least as indicated by the plot)
I tried to add code to perform X and Y interpolation.
q_int = pd.DataFrame(q).interpolate(method='linear', axis=0).values
q_int = pd.DataFrame(q_intx).interpolate(method='linear', axis=1).values
fig= plt.figure(1)
im= plt.imshow(q_int[::-1], cmap='rainbow', interpolation='none', extent=[-search_size,search_size,-search_size,search_size])
But results still were corrupted.
Best,
Gert
You can initialize the array with NaN easily:
shape = (2*search_size, 2*search_size)
q = np.full(shape, np.nan)
This can then be searched as normal. To find the minimum indices ignoring NaNs, you can use np.nanargmin()
In [12]: np.nanargmin([1,-1,4,float('nan')])
Out[12]: 1
To get rid of these NaN values we can use, pandas.DataFrame.interpolate():
q_interpolated = pd.DataFrame(q).interpolate(method='linear', axis=0).values

Interpolation and Root Finding

For an assignment I had to interpolate data [linear interpolation and cubic interpolation] and create two graphs that showed the data as points and the interpolation as a line. I also had to plot the max value of the data. I got all of this to work, but was assigned a last part for extra credit and could not figure it out. V represents the voltage and I represents the current.
Extra assignment: Expand your program so that it also determines the maximum current, and the corresponding voltage, using a different method known as “root finding”. To accomplish this, you will need to numerically differentiate the function. (The numpy function named “diff” will be useful.) Then to carry out the root finding, you can use the “brentq” function From the scipy.optimize library.
from pylab import *
from scipy.interpolate import interp1d
from scipy.optimize import brentq
#load text into two variables V[Voltage] and I[Current]
V, I = loadtxt('data1(1).txt', unpack = True, skiprows = 1)
#voltage and current interpolated[linear]
f_line = interp1d(V, I, 'linear')
new_V = linspace(0, 12, 1000) #array of new voltages created
new_I = f_line(new_V) #array of new currents created from interpolated data
#voltage, current, new voltage, and new current plotted.
plot(V, I, 'ro', new_V, new_I, 'b-')
plot(max(new_I), 'go') #max current plotted
title("Linear Interpolation")
xlabel("Voltage (V)")
xlim(0,12)
ylabel("Current (mA)")
legend(['Data', 'linear Interp', 'Max Current'], loc = 'best')
show()
print "The maximum current is", max(new_I), "mA"
#voltage and current interpolated[cubic]
f_cube = interp1d(V, I, 'cubic')
new_V = linspace(0, 12, 1000) #array of new voltages created
new_I = f_cube(new_V) #array of new currents created from interpolated data
index = argmax(new_I) #index of max current
#voltage, current, new voltage, and new current plotted.
plot(V, I, 'ro', new_V, new_I, 'b-')
plot(new_V[index], max(new_I), 'go') #max current and voltage plotted
title("Cubic Interpolation")
xlabel("Voltage (V)")
xlim(0,12)
ylabel("Current (mA)")
ylim(0,1.4)
legend(['Data', 'linear Interp', 'Max Current'], loc = 'best')
show()
print "The maximum current is", max(new_I), "mA"
print "The corresponding maxium voltage is", new_V[index], "V"
All the above code works, but it's the last part I'm unsure how to start on. I'd appreciate any suggestions or help. I did attempt it, but it threw an error and I was really unsure of how to handle it, as I don't know much about the functions (diff, brentq) being used, or how to use them to find the max current and voltage.
#load text into two variables V[Voltage] and I[Current]
V, I = loadtxt('data1(1).txt', unpack = True, skiprows = 1)
f_line = interp1d(V, I, 'linear')
new_V = linspace(0, 12, 1000) #array of new voltages created
d = diff(new_V, 1)
r = brentq(d)
print r
10 d = diff(new_V, 1)
11
---> 12 r = brentq(d)
13 print r
TypeError: brentq() takes at least 3 arguments (1 given)
I understand what the error is saying, but I don't really know know the correct arguments to give it in order to find the max current and voltage by "root finding" as was asked. Any suggestions are appreciated.

Categories

Resources