Creating the proper axis labels and understanding them - python

I had to create a contour graph (in python) based on a formula and several other parameters. My graph came out fine. However, my axis labels will not show. I have tried changing the code several times but I am actually a little lost as how to what my real problem is. I know it deals with the command to create the labels but understand the error message
Also, this is my first post and if you have recommendations for how I should ask questions, I would appreciate the help.
def contourf_plot():
T = np.linspace(0,30,50)
P = np.linspace(600,1000,50)
X, Y = np.meshgrid(T,P)
Z = (Y/100)*np.e**((12*X)/(X+243))
Z.shape
plt.figure()
CF = plt.contourf(T,P,Z,50)
plt.colorbar(CF)
plt.set_Tlabel("Temperature[$\degree$C]")
plt.set_Plabel("Pressure[Pa]")
plt.show()
return
if __name__ == "__main__":
contourf_plot()
Error message: 'module' object has no attribute 'set_Xlabel'

All you need to do is a slight change in your code. You are currently trying to add a label to the axes T and P, though they do not exist (it is still the x and y axes). T and P are just the data that you are trying to plot.
def contourf_plot():
T = np.linspace(0,30,50)
P = np.linspace(600,1000,50)
X, Y = np.meshgrid(T,P)
Z = (Y/100)*np.e**((12*X)/(X+243))
Z.shape
fig,ax = plt.subplots() #add this line
CF = plt.contourf(T,P,Z,50)
plt.colorbar(CF)
ax.set_xlabel("Temperature[$\degree$C]") #sets the x and y label
ax.set_ylabel("Pressure[Pa]")
plt.show()
return
if __name__ == "__main__":
contourf_plot()
This gives the image

Related

AttributeError: 'Line3D' object has no attribute '_verts3d'

I've been trying to draw a regression line for a multivariable regression, both ENGINESIZE and FUELCONSUMPTION_CITY are independent variables and CO2EMISSIONis the dependent variable.
I was trying to draw a regression line but no matter what, I'm not able to draw it as it keeps showing me the same error.
Below is my code:-
z_cord = regr.coef_[0][0]*train_engine[['ENGINESIZE']]
z_cod = regr.coef_[0][1]*train_engine[['FUELCONSUMPTION_CITY']]
s = y_cord.add(y_cod, fill_value=0)
l = []
for index, row in s.iterrows():
l.append(row['ENGINESIZE']+row['FUELCONSUMPTION_CITY'] + regr.intercept_)
z = pd.DataFrame(l,columns=['CO2EMISSION'])
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.scatter(data[['ENGINESIZE']],data[['FUELCONSUMPTION_CITY']],co2_data)
x = train_engine[['ENGINESIZE']]
y = train_engine[['FUELCONSUMPTION_CITY']]
ax.plot3D(x,y,z,color='red')
plt.show()
Every time i run it its giving me these errors
ValueError: input operand has more dimensions than allowed by the axis remapping
AttributeError: 'Line3D' object has no attribute '_verts3d'
the scatter plot is drawn when i comment ax.plot3D(x,y,z,color='red') line.
I don't know where I'm going wrong, some help would be appreciated.
In your code, x and y are two-dimensional. However, ax.plot3D requires x and y to be one-dimensional and you can make them one-dimensional by:
x = train_engine['ENGINESIZE']
y = train_engine['FUELCONSUMPTION_CITY']
Note that we can get number of dimensions of x and y by ndim:
x.ndim, y.ndim

"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

How do I change the data display format for a imshow plot in matplotlib?

Or more specifically, how can I change the [659] on the upper-right corner to '659 degrees' or something like that ?
I have checked all the threads mentioned in the following reply: matplotlib values under cursor. However, all of them seem to address the x,y location of the cursor. I am interested in changing the data-value. I could not find a reply or related documentation in the api.
I have tried both format_coord(x, y) and format_cursor_data(data) but neither of them seem to be working.
Thanks,
Sarith
PS: My code is in multiple modules and is a part of gui application. I can share relevant sections if that would be of any help in answering this.
One line solution:
ax.format_coord = lambda x, y: 'x={:.2f}, y={:.2f}, z={:.2f}'.format(x,y,data[int(y + 0.5),int(x + 0.5)])
I had the same problem (I wanted to get rid of the data and send it to somewhere else in a tkinter widget).
I figured out the ax.format_coord was'nt being called, the one you have to change is the one at matplotlib.artist.Artist
this worked for me:
def format_cursor_data(self,data):
return 'new_data'
matplotlib.artist.Artist.format_cursor_data=format_cursor_data
By modifying an example from matplotlib I got this code:
This displays x,y, and z value with a degrees after z.
You should be able to easily modify it, or copy the relevant functions to make it work on your side.
You said you already tried format_coord, maybe you forgot to set the funtion? (second last line)
"""
Show how to modify the coordinate formatter to report the image "z"
value of the nearest pixel given x and y
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
X = 10*np.random.rand(5, 3)
fig, ax = plt.subplots()
ax.imshow(X, cmap=cm.jet, interpolation='nearest')
numrows, numcols = X.shape
def format_coord(x, y):
col = int(x + 0.5)
row = int(y + 0.5)
if col >= 0 and col < numcols and row >= 0 and row < numrows:
#get z from your data, given x and y
z = X[row, col]
#this only leaves two decimal points for readability
[x,y,z]=map("{0:.2f}".format,[x,y,z])
#change return string of x,y and z to whatever you want
return 'x='+str(x)+', y='+str(y)+', z='+str(z)+" degrees"
else:
return 'x=%1.4f, y=%1.4f' % (x, y)
#Set the function as the one used for display
ax.format_coord = format_coord
plt.show()
Emmm, Sarith, I am also facing the problem but a little trick helped me out. I still used this function:
your_imshow.format_coord = lambda x, y: 'x={:.5f}, y={:.2f}, amplitude='.format(x,y)
It pretends to add label before the bracket. Yeah, it is an easy but not essential way to change the presentation form, but it works to me. I hope this could also benefit others.

get bins coordinates with hexbin in matplotlib

I use matplotlib's method hexbin to compute 2d histograms on my data.
But I would like to get the coordinates of the centers of the hexagons in order to further process the results.
I got the values using get_array() method on the result, but I cannot figure out how to get the bins coordinates.
I tried to compute them given number of bins and the extent of my data but i don't know the exact number of bins in each direction. gridsize=(10,2) should do the trick but it does not seem to work.
Any idea?
I think this works.
from __future__ import division
import numpy as np
import math
import matplotlib.pyplot as plt
def generate_data(n):
"""Make random, correlated x & y arrays"""
points = np.random.multivariate_normal(mean=(0,0),
cov=[[0.4,9],[9,10]],size=int(n))
return points
if __name__ =='__main__':
color_map = plt.cm.Spectral_r
n = 1e4
points = generate_data(n)
xbnds = np.array([-20.0,20.0])
ybnds = np.array([-20.0,20.0])
extent = [xbnds[0],xbnds[1],ybnds[0],ybnds[1]]
fig=plt.figure(figsize=(10,9))
ax = fig.add_subplot(111)
x, y = points.T
# Set gridsize just to make them visually large
image = plt.hexbin(x,y,cmap=color_map,gridsize=20,extent=extent,mincnt=1,bins='log')
# Note that mincnt=1 adds 1 to each count
counts = image.get_array()
ncnts = np.count_nonzero(np.power(10,counts))
verts = image.get_offsets()
for offc in xrange(verts.shape[0]):
binx,biny = verts[offc][0],verts[offc][1]
if counts[offc]:
plt.plot(binx,biny,'k.',zorder=100)
ax.set_xlim(xbnds)
ax.set_ylim(ybnds)
plt.grid(True)
cb = plt.colorbar(image,spacing='uniform',extend='max')
plt.show()
I would love to confirm that the code by Hooked using get_offsets() works, but I tried several iterations of the code mentioned above to retrieve center positions and, as Dave mentioned, get_offsets() remains empty. The workaround that I found is to use the non-empty 'image.get_paths()' option. My code takes the mean to find centers but which means it is just a smidge longer, but it does work.
The get_paths() option returns a set of x,y coordinates embedded that can be looped over and then averaged to return the center position for each hexagram.
The code that I have is as follows:
counts=image.get_array() #counts in each hexagon, works great
verts=image.get_offsets() #empty, don't use this
b=image.get_paths() #this does work, gives Path([[]][]) which can be plotted
for x in xrange(len(b)):
xav=np.mean(b[x].vertices[0:6,0]) #center in x (RA)
yav=np.mean(b[x].vertices[0:6,1]) #center in y (DEC)
plt.plot(xav,yav,'k.',zorder=100)
I had this same problem. I think what needs to be developed is a framework to have a HexagonalGrid object which can then be applied to many different data sets (and it would be awesome to do it for N dimensions). This is possible and it surprises me that neither Scipy or Numpy has anything for it (furthermore there seems to be nothing else like it except perhaps binify)
That said, I assume you want to use hexbinning to compare multiple binned data sets. This requires some common base. I got this to work using matplotlib's hexbin the following way:
import numpy as np
import matplotlib.pyplot as plt
def get_data (mean,cov,n=1e3):
"""
Quick fake data builder
"""
np.random.seed(101)
points = np.random.multivariate_normal(mean=mean,cov=cov,size=int(n))
x, y = points.T
return x,y
def get_centers (hexbin_output):
"""
about 40% faster than previous post only cause you're not calculating the
min/max every time
"""
paths = hexbin_output.get_paths()
v = paths[0].vertices[:-1] # adds a value [0,0] to the end
vx,vy = v.T
idx = [3,0,5,2] # index for [xmin,xmax,ymin,ymax]
xmin,xmax,ymin,ymax = vx[idx[0]],vx[idx[1]],vy[idx[2]],vy[idx[3]]
half_width_x = abs(xmax-xmin)/2.0
half_width_y = abs(ymax-ymin)/2.0
centers = []
for i in xrange(len(paths)):
cx = paths[i].vertices[idx[0],0]+half_width_x
cy = paths[i].vertices[idx[2],1]+half_width_y
centers.append((cx,cy))
return np.asarray(centers)
# important parts ==>
class Hexagonal2DGrid (object):
"""
Used to fix the gridsize, extent, and bins
"""
def __init__ (self,gridsize,extent,bins=None):
self.gridsize = gridsize
self.extent = extent
self.bins = bins
def hexbin (x,y,hexgrid):
"""
To hexagonally bin the data in 2 dimensions
"""
fig = plt.figure()
ax = fig.add_subplot(111)
# Note mincnt=0 so that it will return a value for every point in the
# hexgrid, not just those with count>mincnt
# Basically you fix the gridsize, extent, and bins to keep them the same
# then the resulting count array is the same
hexbin = plt.hexbin(x,y, mincnt=0,
gridsize=hexgrid.gridsize,
extent=hexgrid.extent,
bins=hexgrid.bins)
# you could close the figure if you don't want it
# plt.close(fig.number)
counts = hexbin.get_array().copy()
return counts, hexbin
# Example ===>
if __name__ == "__main__":
hexgrid = Hexagonal2DGrid((21,5),[-70,70,-20,20])
x_data,y_data = get_data((0,0),[[-40,95],[90,10]])
x_model,y_model = get_data((0,10),[[100,30],[3,30]])
counts_data, hexbin_data = hexbin(x_data,y_data,hexgrid)
counts_model, hexbin_model = hexbin(x_model,y_model,hexgrid)
# if you want the centers, they will be the same for both
centers = get_centers(hexbin_data)
# if you want to ignore the cells with zeros then use the following mask.
# But if want zeros for some bins and not others I'm not sure an elegant way
# to do this without using the centers
nonzero = counts_data != 0
# now you can compare the two data sets
variance_data = counts_data[nonzero]
square_diffs = (counts_data[nonzero]-counts_model[nonzero])**2
chi2 = np.sum(square_diffs/variance_data)
print(" chi2={}".format(chi2))

Graphing a line and scatter points using Matplotlib?

I'm using matplotlib at the moment to try and visualise some data I am working on. I'm trying to plot around 6500 points and the line y = x on the same graph but am having some trouble in doing so. I can only seem to get the points to render and not the line itself. I know matplotlib doesn't plot equations as such rather just a set of points so I'm trying to use and identical set of points for x and y co-ordinates to produce the line.
The following is my code
from matplotlib import pyplot
import numpy
from pymongo import *
class Store(object):
"""docstring for Store"""
def __init__(self):
super(Store, self).__init__()
c = Connection()
ucd = c.ucd
self.tweets = ucd.tweets
def fetch(self):
x = []
y = []
for t in self.tweets.find():
x.append(t['positive'])
y.append(t['negative'])
return [x,y]
if __name__ == '__main__':
c = Store()
array = c.fetch()
t = numpy.arange(0., 0.03, 1)
pyplot.plot(array[0], array[1], 'ro', t, t, 'b--')
pyplot.show()
Any suggestions would be appreciated,
Patrick
Correct me if I'm wrong (I'm not a pro at matplotlib), but 't' will simply get the value [0.].
t = numpy.arange(0.,0.03,1)
That means start at 0 and go to 0.03 (not inclusive) with a step size of 1. Resulting in an array containing just 0.
In that case you are simply plotting one point. It takes two to make a line.

Categories

Resources