Plotting multiple ellipses on same figure with data from text file - python

I am new to python, so I am sorry if this is too trivial.
This is an example of the first two lines of the text file.
ra dec major_axis minor_axis position_angle
149.20562 2.29594 0.00418 0.00310 83.40
Each line of the file has 5 parameters which is needed to plot one ellipse. The first two columns are for the center. The next 3 columns are major axis, minor axis and position angle respectively. This file is part of a huge catalog which has many lines. I want to plot all those ellipses in one figure.
Here is what I tried.
import matplotlib.pyplot as plt
import numpy as np
import astropy.io.ascii as asciitable
from matplotlib.patches import Ellipse
path=/users/vishnu/Desktop/
fw=open(path + 'data_plot.txt', 'r')
table = asciitable.read(path+ "data_plot.txt")
ra_degrees=[table['ra']]
dec_degrees=[table['dec']]
major_axis_deg=[table['major_axis']]
minor_axis_deg=[table['minor_axis']]
position_angle_deg=[table['position_angle']]
for ra, dec, w, h, angle in zip(ra_degrees,
dec_degrees,major_axis_deg, minor_axis_deg, position_angle_deg):
ellipse = Ellipse(xy=(ra, dec), width=w, height=h, angle=angle)
ax.add_patch(ellipse)
plt.axis('scaled')
plt.show()
fw.close()
This is the error log.
runfile('/users/vishnu/.spyder2-py3/radio_sources.py', wdir='/users/vishnu/.spyder2-py3')
Traceback (most recent call last):
File "<ipython-input-299-a0011c0326f5>", line 1, in <module>
runfile('/users/vishnu/.spyder2-py3/radio_sources.py', wdir='/users/vishnu/.spyder2-py3')
File "/users/vishnu/anaconda3/lib/python3.5/site-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 699, in runfile
execfile(filename, namespace)
File "/users/vishnu/anaconda3/lib/python3.5/site-packages/spyderlib/widgets/externalshell/sitecustomize.py", line 88, in execfile
exec(compile(open(filename, 'rb').read(), filename, 'exec'), namespace)
File "/users/vishnu/.spyder2-py3/radio_sources.py", line 63, in <module>
ax.add_patch(ellipse)
File "/users/vishnu/anaconda3/lib/python3.5/site-packages/matplotlib/axes/_base.py", line 1783, in add_patch
self._update_patch_limits(p)
File "/users/vishnu/anaconda3/lib/python3.5/site-packages/matplotlib/axes/_base.py", line 1803, in _update_patch_limits
xys = patch.get_patch_transform().transform(vertices)
File "/users/vishnu/anaconda3/lib/python3.5/site-packages/matplotlib/patches.py", line 1409, in get_patch_transform
self._recompute_transform()
File "/users/vishnu/anaconda3/lib/python3.5/site-packages/matplotlib/patches.py", line 1398, in _recompute_transform
.scale(width * 0.5, height * 0.5) \
File "/users/vishnu/anaconda3/lib/python3.5/site-packages/matplotlib/transforms.py", line 1965, in scale
np.float_)
ValueError: setting an array element with a sequence.
Please also let me know if there is a smarter way to do this without the need to create arrays.

I'm guessing the problem is that you have one too many levels of nesting on ra_degrees, etc.
That is, if you print table['ra'] you will probably find that it is already an array. When you enclose it in square brackets, [table['ra']] will then be a list of length one. The zip function takes one item from each sequence at a time, so in your for loop, ra will be assigned table['ra'] the first and only time through the loop.
Another issue is that you are opening the file twice. You are passing the filename to asciitable.read, and are never actually using fw.
The code below might work better.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
import astropy.io.ascii as asciitable
path=/users/vishnu/Desktop/
table = asciitable.read(path + "data_plot.txt")
ra_degrees = table['ra']
dec_degrees = table['dec']
major_axis_deg = table['major_axis']
minor_axis_deg = table['minor_axis']
position_angle_deg = table['position_angle']
for ra, dec, w, h, angle in zip(ra_degrees, dec_degrees,
major_axis_deg, minor_axis_deg, position_angle_deg):
ellipse = Ellipse(xy=(ra, dec), width=w, height=h, angle=angle)
ax.add_patch(ellipse)
plt.axis('scaled')
plt.show()
If asciitable works with an open file rather than a file name, then use the following instead:
with open(path + "data_plot.txt") as fw:
table = asciitable.read(fw)
This makes sure that the file is closed even if there are errors in asciitable.read that cause it to raise an exception. Given the error above, though, it looks like you have already read the data.

Seems like you need to use a PatchCollection, see this example. Try something like this
plt.figure()
ax = plt.gca()
ellipses = []
plt.xlim([0,100])
plt.ylim([0,100])
for ra, dec, w ... zip(...):
ellipse = Ellipse(xy=(ra, dec), width=w, height=h, angle=angle)
ellipses.append(ellipse)
p = PatchCollection(ellipses)
ax.add_collection(p)
plt.show()

Related

VALUE ERROR: x, y, and format string must not be None. (error while plotting hysteresis loop)

With the low cycle fatigue data, I'm trying to plot the Hysteresis loop. But I'm getting the following error:
[ -52.18297297 -45.58565338 16.9913185 ... -354.53630032 -295.50857248
-155.42088911]
[-0.01229182 -0.00891753 0.02256744 ... -0.33507242 -0.31283728
-0.24790212]
Traceback (most recent call last):
File "f:\I2M\LCF\Ep1_camp4_P4_TTH650 06-9-21 11 01 24\ep1_camp4_P4.py", line 16, in <module>
plt.plot(strain, Sigma, color = 'k')
File "C:\Users\DELL\AppData\Local\Programs\Python\Python39\lib\site-
packages\matplotlib\pyplot.py", line 2840, in plot
return gca().plot(
File "C:\Users\DELL\AppData\Local\Programs\Python\Python39\lib\site-
packages\matplotlib\axes\_axes.py", line 1743, in plot
lines = [*self._get_lines(*args, data=data, **kwargs)]
File "C:\Users\DELL\AppData\Local\Programs\Python\Python39\lib\site-
packages\matplotlib\axes\_base.py", line 273, in __call__
yield from self._plot_args(this, kwargs)
File "C:\Users\DELL\AppData\Local\Programs\Python\Python39\lib\site-
packages\matplotlib\axes\_base.py", line 379, in _plot_args
raise ValueError("x, y, and format string must not be None")
ValueError: x, y, and format string must not be None
And here is my code:
import matplotlib.pyplot as plt
import numpy as np
plt.style.use(['science','no-latex'])
x = np.loadtxt('F:\\I2M\\LCF\\Ep1_camp4_P4_TTH650 06-9-21 11 01 24\\data_1.csv',unpack = True,
skiprows = 2, usecols = 2, delimiter = ',')
y = np.loadtxt('F:\\I2M\\LCF\\Ep1_camp4_P4_TTH650 06-9-21 11 01 24\\data_1.csv',unpack = True,
skiprows = 2, usecols = 3, delimiter = ',')
stress = (x*1000)/28.27 #N/mm^2 = MPa
length = len(stress)
length = len(y)
plt.figure(figsize=(5, 5))
Sigma = print(stress[0:length:10]) #stress
strain = print(y[0:length:10])
plt.plot(strain, Sigma, color = 'k')
plt.show()
Data contains many rows. So I used some commands to access only particular values from the row
Your problem is here
Sigma = print(stress[0:length:10]) #stress
strain = print(y[0:length:10])
what you want plausibly is to sample every 10th data point, but what you get is … nothing or, from the point of view of Python: None, so that later your stack trace informs you that x, y, and format string must not be None.
Why this happens, and how you solve the problem?
When you make an assignment, the value of the expression on the right is saved and you can use the name on the left to use it later, so you save, e.g., the value returned by print(y[0:length:10]) to use it later under the name strain, but print() is used for its side effects (i.e., showing a bunch of characters on your terminal) and the value that is returned in these cases is by default None, not what was shown on your terminal.
If I have understood your intentions, you should omit the two lines above and just use
plt.plot(x[0:length:10], y[0:length:10], color='k')
A side note, you have
length = len(stress)
length = len(y)
but you read them from the same file, one assignment should be enough…
PS
x, y = np.loadtxt('…\\data_1.csv', unpack=1, skiprows=2, usecols=[2,3], delimiter=',')

Need help in ploting PSD(Power spectral density) on python

This is my code to plot a Power spectral density signal. I need some help as im having error coding in python.
import math
import numpy as np
import matplotlib.pyplot as plt
from numpy.fft import fft, ifft
from scipy import signal
t=np.linspace(0,1,106)
Fs=1000
y=np.sin(2*math.pi*15*t) + np.sin(2*math.pi*30*t)
Y=fft(y,512)
f = np.arange(0,len(Y)-1)*(Fs-1)/len(Y)
P = abs(Y)*2/len(Y)
plt.plot(f,P)
plt.show()
This is the error i have when i try to run it.
Traceback (most recent call last):
File "C:\Users\keehu\Desktop\trial.py", line 13, in <module>
plt.plot(f,P)
File "C:\Users\keehu\AppData\Local\Programs\Python\Python38-32\lib\site-packages\matplotlib\pyplot.py", line 2761, in plot
return gca().plot(
File "C:\Users\keehu\AppData\Local\Programs\Python\Python38-32\lib\site-packages\matplotlib\axes\_axes.py", line 1646, in plot
lines = [*self._get_lines(*args, data=data, **kwargs)]
File "C:\Users\keehu\AppData\Local\Programs\Python\Python38-32\lib\site-packages\matplotlib\axes\_base.py", line 216, in __call__
yield from self._plot_args(this, kwargs)
File "C:\Users\keehu\AppData\Local\Programs\Python\Python38-32\lib\site-packages\matplotlib\axes\_base.py", line 342, in _plot_args
raise ValueError(f"x and y must have same first dimension, but "
ValueError: x and y must have same first dimension, but have shapes (511,) and (512,)
>>>
Your f is of size len(Y)-1 as you requested, but P has size len(Y).
The size of f is 511 and Y is 512. I have changed the code to solve that.
import math
import numpy as np
import matplotlib.pyplot as plt
from numpy.fft import fft, ifft
from scipy import signal
t=np.linspace(0,1,106)
Fs=1000
y=np.sin(2*math.pi*15*t) + np.sin(2*math.pi*30*t)
Y=fft(y,512)
f = np.arange(0,len(Y))*(Fs-1)/len(Y) #changed here
P = abs(Y)*2/len(Y)
plt.plot(f,P)
plt.show()
"ValueError: x and y must have same first dimension, but have shapes (511,) and (512,)" means that your arrays, f and P don't have the same size. f is one element to small. Use:
f = np.arange(0,len(Y))*(Fs-1)/len(Y)

ValueError when using lmfit LognormalModel

I have been using lmfit for about a day now and needless to say I know very little about the library. I have been using several built-in models for curve fitting and all of them work flawlessly with the data except the Lognormal Model.
Here is my code:
from numpy import *
from lmfit.models import LognormalModel
import pandas as pd
import scipy.integrate as integrate
import matplotlib.pyplot as plt
data = pd.read_csv('./data.csv', delimiter = ",")
x = data.ix[:, 0]
y = data.ix[:, 1]
print (x)
print (y)
mod = LognormalModel()
pars = mod.guess(y, x=x)
out = mod.fit(y, pars , x=x)
print(out.best_values)
print(out.fit_report(min_correl=0.25))
out.plot()
plt.plot(x, y, 'bo')
plt.plot(x, out.init_fit, 'k--')
plt.plot(x, out.best_fit, 'r-')
plt.show()
and the error output is:
Traceback (most recent call last):
File "Cs_curve_fit.py", line 17, in <module>
pvout = pvmod.fit(y, amplitude= 1, center = 1, sigma =1 , x=x)
File "C:\Users\NAME\Anaconda3\lib\site-packages\lmfit\model.py", line 731, in fit
output.fit(data=data, weights=weights)
File "C:\Users\NAME\Anaconda3\lib\site-packages\lmfit\model.py", line 944, in fit
self.init_fit = self.model.eval(params=self.params, **self.userkws)
File "C:\Users\NAME\Anaconda3\lib\site-packages\lmfit\model.py", line 569, in eval
return self.func(**self.make_funcargs(params, kwargs))
File "C:\Users\NAME\Anaconda3\lib\site-packages\lmfit\lineshapes.py", line 162, in lognormal
x[where(x <= 1.e-19)] = 1.e-19
File "C:\Users\NAME\Anaconda3\lib\site-packages\pandas\core\series.py", line 773, in __setitem__
setitem(key, value)
File "C:\Users\NAME\Anaconda3\lib\site-packages\pandas\core\series.py", line 755, in setitem
raise ValueError("Can only tuple-index with a MultiIndex")
ValueError: Can only tuple-index with a MultiIndex
First, the error message you show cannot have come from the code you post. The error message says that line 17 of the file "Cs_curve_fit.py" reads
pvout = pvmod.fit(y, amplitude= 1, center = 1, sigma =1 , x=x)
but that is not anywhere in your code. Please post the actual code and the actual output.
Second, the problem appears to happening because the data for x is cannot be turned into a 1D numpy array. Not being able to trust your code or output, I would just suggest converting the data to 1D numpy arrays yourself as a first test. Lmfit should be able to handle Pandas series, but it just does a simple coercion to 1D numpy arrays.

Python Plot sees Reals but Bar sees Strings

In short, when I use the plot command, my data is recognized as real double precision numbers, but asking for a bar graph for some reason returns the complaint that the data are strings, not reals. Here is my simple code:
#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
#for counter in range(102,401):
for counter in range(400,401):
temp1=str(counter)
temp="column_1_file_"+temp1
temp2="column_2_file_"+temp1
xdata=np.loadtxt(temp,delimiter=" ",dtype=str)
ydata=np.loadtxt(temp2,delimiter=" ",dtype=str)
plt.plot(xdata,ydata,'or')
# width=1.0
# plt.bar(xdata,ydata,width,color="blue")
plt.xlabel(r' Particle Radius ($\mu$m)')
plt.ylabel("Frequency")
plt.title("Histogram of Particle Radius")
plt.xlim(-1,40)
plt.ylim(0,1.1)
# plt.show()
var1=str(counter)+".png"
plt.savefig(var1,format='png')
counter=counter+1
When executed, the program above works fine, producing the desired line plot just fine. When I comment out "plt.plot(xdata,ydata,'or')" and un-comment the plt.bar and width lines, I get the below error:
On the command line, the commands and responses given are:
python Histogram_Evolution.py
Traceback (most recent call last):
File "Histogram_Evolution.py", line 13, in <module>
plt.bar(xdata,ydata,width,color="blue")
File "/N/soft/rhel6/python/2.7.3/lib/python2.7/site-packages/matplotlib- 1.3.1-py2.7-linux-x86_64.egg/matplotlib/pyplot.py", line 2515, in bar
ret = ax.bar(left, height, width=width, bottom=bottom, **kwargs)
File "/N/soft/rhel6/python/2.7.3/lib/python2.7/site-packages/matplotlib-1.3.1-py2.7-linux-x86_64.egg/matplotlib/axes.py", line 5053, in bar
self.add_patch(r)
File "/N/soft/rhel6/python/2.7.3/lib/python2.7/site-packages/matplotlib-1.3.1-py2.7-linux-x86_64.egg/matplotlib/axes.py", line 1562, in add_patch
self._update_patch_limits(p)
File "/N/soft/rhel6/python/2.7.3/lib/python2.7/site-packages/matplotlib-1.3.1-py2.7-linux-x86_64.egg/matplotlib/axes.py", line 1580, in _update_patch_limits
xys = patch.get_patch_transform().transform(vertices)
File "/N/soft/rhel6/python/2.7.3/lib/python2.7/site-packages/matplotlib-1.3.1-py2.7-linux-x86_64.egg/matplotlib/patches.py", line 576, in get_patch_transform
self._update_patch_transform()
File "/N/soft/rhel6/python/2.7.3/lib/python2.7/site-packages/matplotlib-1.3.1-py2.7-linux-x86_64.egg/matplotlib/patches.py", line 569, in _update_patch_transform
bbox = transforms.Bbox.from_bounds(x, y, width, height)
File "/N/soft/rhel6/python/2.7.3/lib/python2.7/site-packages/matplotlib-1.3.1-py2.7-linux-x86_64.egg/matplotlib/transforms.py", line 821, in from_bounds
return Bbox.from_extents(x0, y0, x0 + width, y0 + height)
TypeError: cannot concatenate 'str' and 'float' objects
Here is an example of the xdata file that is read, followed by an example of the ydata file that is read:
0.3454E-03
0.3801E-03
0.4095E-03
0.4245E-03
0.4456E-03
0.4661E-03
0.4861E-03
0.5049E-03
0.5292E-03
0.5435E-03
0.5588E-03
0.5732E-03
0.5840E-03
0.5925E-03
0.6037E-03
0.6158E-03
0.6852E-03
0.9102E-03
0.1083E-02
0.1197E-02
0.1306E-02
0.1477E-02
0.1986E-02
0.2352E-02
0.2577E-02
0.2810E-02
0.3253E-02
0.4226E-02
0.5017E-02
0.5535E-02
0.6018E-02
0.6973E-02
0.9046E-02
0.1079E-01
0.1192E-01
0.1294E-01
0.1502E-01
0.1948E-01
0.2325E-01
0.2568E-01
0.2789E-01
0.3235E-01
0.4198E-01
0.5012E-01
0.5532E-01
0.6012E-01
0.781791E-01
0.782330E-01
0.105108E-02
0.108144E-02
0.180879E-04
0.544883E-03
0.545426E-03
0.544242E-04
0.298458E-06
0.287814E-06
0.329474E-06
0.473319E-07
0.829702E-07
0.123443E-08
0.411156E-07
0.421080E-07
0.218848E+00
0.279559E+00
0.234184E+00
0.291552E+00
0.240008E+00
0.449513E+00
0.485745E+00
0.434142E+00
0.473585E+00
0.457689E+00
0.576471E+00
0.551371E+00
0.493782E+00
0.456229E+00
0.409499E+00
0.497298E+00
0.529838E+00
0.529549E+00
0.533233E+00
0.531061E+00
0.635727E+00
0.654071E+00
0.653801E+00
0.655098E+00
0.653899E+00
0.712113E+00
0.721604E+00
0.721187E+00
0.721345E+00
0.726954E+00
0.793069E+00
0.806902E+00
0.805833E+00
Matplotlib's plot has a convenience function integrated that automatically converts strings to numbers. bar does not have this functionality. So in order to plot a bar plot, you need to use numerical data.
This shouldn't be a problem, just don't specify str as dtype when reading in the data
np.loadtxt(temp,delimiter=" ")

How to make grouper and axis the same length?

For my assignment I'm supposed to plot the tracks of 20 hurricanes on a map using matplotlib. However when I run my code I get the error: AssertionError:Grouper and axis must be the same length
Here's the code I have:
import numpy as np
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from PIL import *
fig = plt.figure(figsize=(12,12))
ax = fig.add_axes([0.1,0.1,0.8,0.8])
m = Basemap(llcrnrlon=-100.,llcrnrlat=0.,urcrnrlon=-20.,urcrnrlat=57.,
projection='lcc',lat_1=20.,lat_2=40.,lon_0=-60.,
resolution ='l',area_thresh=1000.)
m.bluemarble()
m.drawcoastlines(linewidth=0.5)
m.drawcountries(linewidth=0.5)
m.drawstates(linewidth=0.5)
# Creates parallels and meridians
m.drawparallels(np.arange(10.,35.,5.),labels=[1,0,0,1])
m.drawmeridians(np.arange(-120.,-80.,5.),labels=[1,0,0,1])
m.drawmapboundary(fill_color='aqua')
# Opens data file
import pandas as pd
name = [ ]
df = pd.read_csv('louisianastormb.csv')
for name, group in df.groupby([name]):
latitude = group.lat.values
longitude = group.lon.values
x,y = m(longitude, latitude)
plt.plot(x,y,'y-',linewidth=2 )
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plt.title('20 Hurricanes with Landfall in Louisiana')
plt.savefig('20hurpaths.jpg', dpi=100)
Here's the full error output:
Traceback (most recent call last):
File "/home/darealmzd/lstorms.py", line 31, in <module>
for name, group in df.groupby([name]):
File "/usr/local/lib/python2.7/dist-packages/pandas/core/generic.py", line 186, in groupby
squeeze=squeeze)
File "/usr/local/lib/python2.7/dist-packages/pandas/core/groupby.py", line 533, in groupby
return klass(obj, by, **kwds)
File "/usr/local/lib/python2.7/dist-packages/pandas/core/groupby.py", line 197, in __init__
level=level, sort=sort)
File "/usr/local/lib/python2.7/dist-packages/pandas/core/groupby.py", line 1325, in _get_grouper
ping = Grouping(group_axis, gpr, name=name, level=level, sort=sort)
File "/usr/local/lib/python2.7/dist-packages/pandas/core/groupby.py", line 1129, in __init__
self.grouper = _convert_grouper(index, grouper)
File "/usr/local/lib/python2.7/dist-packages/pandas/core/groupby.py", line 1350, in _convert_grouper
raise Assertionerror('Grouper and axis must be same length')
Assertionerror: Grouper and axis must be same length
ValueError: Grouper and axis must be same length
This can occur if you are using double brackets in the groupby argument.
(I posted this since it is the top result on Google).
The problem is that you're grouping by (effectively) a list of empty list ([[]]). Because you have name = [] earlier and then you wrap that in a list as well.
If you want to group on a single column (called 'HurricaneName'), you should do something like:
for name, group in df.groupby('HurricaneName'):
However, if you want to group on multiple columns, then you need to pass a list:
for name, group in df.groupby(['HurricaneName', 'Year'])
If you want to put it in a variable like you have, you can do it like this:
col_name = 'State'
for name, group in df.groupby([col_name]):
Try iloc to make grouper equal to axis.
example:
sns.boxplot(x=df['pH-binned'].iloc[0:3], y=v_count, data=df)
In case axis=3.

Categories