Create a structured array in python - python

I would like to create a dictionary in Python using numpy commands.
First I tried to define the structure and then to populate the array according to a number/case selected by the user. When I try to request one of the cases I get the following error (for case 1):
cannot copy sequence with size 3 to array axis with dimension 1
How can I fix my code in order to be able to store the data I want in my structure? Regardless of the case I select.
Here is my code:
# defining the structure
usgStruct = np.zeros(1,dtype = [("satNr",np.int),
("satAzimuth", np.int),
("satElevation", np.int),
("scenarioEnv", np.str),
("scenarioHead", np.int),
("scenarioLen", np.int),
("speed", np.int)])
def case1():
usgStruct["satNr"] = 3
usgStruct["satAzimuth"] = [180, 200, 235]
usgStruct["satElevation"] = [35, 25, 25]
usgStruct["scenarioEnv"] = ["S", "S", "S", "U", "U"]
usgStruct["scenarioHead"] = [45, 280, 45, 120, 200]
usgStruct["scenarioLen"] = [2000, 500, 3000, 2000, 500]
usgStruct["speed"] = [15, 15, 15, 10, 10]
return usgStruct
def case2():
usgStruct["satNr"] = 2
usgStruct["satAzimuth"] = [180, 225]
usgStruct["satElevation"] = [45, 30]
usgStruct["scenarioEnv"] = ["U", "U", "O", "O", "S", "S", "S"]
usgStruct["scenarioHead"] = [30, 65, 65, 80, 80, 60, 130]
usgStruct["scenarioLen"] = [300, 800, 2000, 1000, 700, 700, 300]
usgStruct["speed"] = [10, 10, 15, 15, 15, 15, 15]
return usgStruct
def case3():
usgStruct["satNr"] = 2
usgStruct["satAzimuth"] = [180, 225]
usgStruct["satElevation"] = [35, 30]
usgStruct["scenarioEnv"] = ['C', 'C', 'C', 'C', 'O']
usgStruct["scenarioHead"] = [90, 45, 120, 70, 45]
usgStruct["scenarioLen"] = [1500, 500, 300, 2000, 3000]
usgStruct["speed"] = [15, 15, 15, 15, 20]
return usgStruct
# set up a dictionary of actions
scenarioGenerator = {
"1": case1,
"2": case2,
"3": case3}
runscenGen = raw_input("Please enter a number from 1 to 7\n ")
scenarioGenerator.get(runscenGen,case3)() # specify a default: case3
print usgStruct

print the initial usgStruct array:
In [329]: usgStruct
Out[329]:
array([(0, 0, 0, '', 0, 0, 0)],
dtype=[('satNr', '<i4'), ('satAzimuth', '<i4'), ('satElevation', '<i4'), ('scenarioEnv', '<U'), ('scenarioHead', '<i4'), ('scenarioLen', '<i4'), ('speed', '<i4')])
Its data is 6 numbers and one character ('U' on my py3). That's all it can hold. It can't hold lists.
Even if you defined it to be size (3,)
In [331]: usgStruct
Out[331]:
array([(0, 0, 0, '', 0, 0, 0), (0, 0, 0, '', 0, 0, 0),
(0, 0, 0, '', 0, 0, 0)],
dtype=[('satNr', '<i4'), ('satAzimuth', '<i4'), ('satElevation', '<i4'), ('scenarioEnv', '<U'), ('scenarioHead', '<i4'), ('scenarioLen', '<i4'), ('speed', '<i4')])
individual records are still this 7 element tuple.
You case data is entirely different. Each case looks like a dictionary with list values. Changing case1 to produce and return a dictionary:
In [334]: def case1():
...: usgStruct={}
...: usgStruct["satNr"] = 3
...: usgStruct["satAzimuth"] = [180, 200, 235]
...: usgStruct["satElevation"] = [35, 25, 25]
...: usgStruct["scenarioEnv"] = ["S", "S", "S", "U", "U"]
...: usgStruct["scenarioHead"] = [45, 280, 45, 120, 200]
...: usgStruct["scenarioLen"] = [2000, 500, 3000, 2000, 500]
...: usgStruct["speed"] = [15, 15, 15, 10, 10]
...: return usgStruct
...:
In [335]: case1()
Out[335]:
{'satAzimuth': [180, 200, 235],
'satElevation': [35, 25, 25],
'satNr': 3,
'scenarioEnv': ['S', 'S', 'S', 'U', 'U'],
'scenarioHead': [45, 280, 45, 120, 200],
'scenarioLen': [2000, 500, 3000, 2000, 500],
'speed': [15, 15, 15, 10, 10]}
Now scenarioGenerator would be a dictionary of dictionaries.

Related

Why is meshgrid changing (x, y, z) order to (y, x, z)?

I have 3 vectors:
u = np.array([0, 100, 200, 300]) #hundreds
v = np.array([0, 10, 20]) #tens
w = np.array([0, 1]) #units
Then I used np.meshgrid to sum u[i]+v[j],w[k]:
x, y, z = np.meshgrid(u, v, w)
func1 = x + y + z
So, when (i,j,k)=(3,2,1), func1[i, j, k] should return 321, but I only get 321 if I put func1[2, 3, 1].
Why is it asking me for vector v before u? Should I use numpy.ix_ instead?
From the meshgrid docs:
Notes
-----
This function supports both indexing conventions through the indexing
keyword argument. Giving the string 'ij' returns a meshgrid with
matrix indexing, while 'xy' returns a meshgrid with Cartesian indexing.
In the 2-D case with inputs of length M and N, the outputs are of shape
(N, M) for 'xy' indexing and (M, N) for 'ij' indexing. In the 3-D case
with inputs of length M, N and P, outputs are of shape (N, M, P) for
'xy' indexing and (M, N, P) for 'ij' indexing.
In [109]: U,V,W = np.meshgrid(u,v,w, sparse=True)
In [110]: U
Out[110]:
array([[[ 0], # (1,4,1)
[100],
[200],
[300]]])
In [111]: U+V+W
Out[111]:
array([[[ 0, 1],
[100, 101],
[200, 201],
[300, 301]],
[[ 10, 11],
[110, 111],
[210, 211],
[310, 311]],
[[ 20, 21],
[120, 121],
[220, 221],
[320, 321]]])
The result is (3,4,2) array; This is the cartesian case described in the notes.
With the documented indexing change:
In [113]: U,V,W = np.meshgrid(u,v,w, indexing='ij',sparse=True)
In [114]: U.shape
Out[114]: (4, 1, 1)
In [115]: (U+V+W).shape
Out[115]: (4, 3, 2)
Which matches the ix_ that you wanted:
In [116]: U,V,W = np.ix_(u,v,w)
In [117]: (U+V+W).shape
Out[117]: (4, 3, 2)
You are welcome to use either. Or even np.ogrid as mentioned in the docs.
Or even the home-brewed broadcasting:
In [118]: (u[:,None,None]+v[:,None]+w).shape
Out[118]: (4, 3, 2)
Maybe the 2d layout clarifies the two coordinates:
In [119]: Out[111][:,:,0]
Out[119]:
array([[ 0, 100, 200, 300], # u going across, x-axis
[ 10, 110, 210, 310],
[ 20, 120, 220, 320]])
In [120]: (u[:,None,None]+v[:,None]+w)[:,:,0]
Out[120]:
array([[ 0, 10, 20], # u going down - rows
[100, 110, 120],
[200, 210, 220],
[300, 310, 320]])
For your indexing method, you need axis 0 to be the direction of increment of 1s, axis 1 to be for 10s, and axis 2 to be for 100s.
You can just transpose to swap the axes to suit your indexing method -
u = np.array([0, 100, 200, 300]) #hundreds
v = np.array([0, 10, 20, 30]) #tens
w = np.array([0, 1, 2, 3]) #units
x,y,z = np.meshgrid(w,v,u)
func1 = x + y + z
func1 = func1.transpose(2,0,1)
func1
# axis 0 is 1s
#------------------>
array([[[ 0, 1, 2, 3],
[ 10, 11, 12, 13], #
[ 20, 21, 22, 23], # Axis 1 is 10s
[ 30, 31, 32, 33]],
[[100, 101, 102, 103], #
[110, 111, 112, 113], # Axis 2 is 100s
[120, 121, 122, 123], #
[130, 131, 132, 133]],
[[200, 201, 202, 203],
[210, 211, 212, 213],
[220, 221, 222, 223],
[230, 231, 232, 233]],
[[300, 301, 302, 303],
[310, 311, 312, 313],
[320, 321, 322, 323],
[330, 331, 332, 333]]])
Testing this by indexing -
>> func1[2,3,1]
231
>> func1[3,2,1]
321

how to remove duplicate numbers? more of the same values

My code combines values from two matrices and lists them side by side. T works as I need properly.
We are trying to remove the field where 2 identical values are located. This can be better seen in the example below
my code
import os
import numpy as np
import sys
b=np.array([[13,14,15],
[22,23,24],
[31,32,33]])
#print(b)
d=np.array([100,200,300,400,500])
b[-1,:] = d[:b.shape[1]] # last row
b[:-1,-1] = d[b.shape[1]:]
val1 = np.hstack(b[::-1])
val2 = np.hstack([d[i:i+b.shape[1]] for i in range(b.shape[0])])
res = zip(val1, val2)
for i, j in res:
l=[i, j]
print(l)
my output
[100, 100]
[200, 200]
[300, 300]
[22, 200]
[23, 300]
[500, 400]
[13, 300]
[14, 400]
[400, 500]
My code combines values from two matrices and lists them side by side. T works as I need properly.
We are trying to remove the field where 2 identical values are located. This can be better seen in the example below
I would need to remove matrices in my output that contain the same numbers. As you can see in the output below
The matrices do not always have to be the same and do not have to match the same iterations
required output
[22, 200]
[23, 300]
[500, 400]
[13, 300]
[14, 400]
[400, 500]
Find where the values are different and only concatenate those values.
>>> # using val1 and val2 from the question
>>> mask = np.where(val1!=val2)
>>> mask
(array([3, 4, 5, 6, 7, 8], dtype=int64),)
>>> np.vstack((val1[mask],val2[mask]))
array([[ 22, 23, 500, 13, 14, 400],
[200, 300, 400, 300, 400, 500]])
>>> np.vstack((val1[mask],val2[mask])).T
array([[ 22, 200],
[ 23, 300],
[500, 400],
[ 13, 300],
[ 14, 400],
[400, 500]])
>>>
It is as simple as comparing the two arrays and using the result as a boolean index:
np.stack([val1, val2], axis=1)[val1 != val2]

How to convert numeric to strings in the box plot

I want to plot the boxplot of the following dataset :
A = [150, 112, 108, 70]
B = [260, 90, 165, 100]
C = [160, 50, 90, 60]
D = [110, 20, 35, 70]
E = [105, 450, 45, 200]
One way I can do it is via the following code:
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager
font_prop = font_manager.FontProperties( size=18)
Positions = [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5]
Heat = [150, 112, 108, 70, 260, 90, 165, 100, 160, 50, 90, 60, 110, 20, 35, 70, 105, 450, 45, 200]
groups = [[] for i in range(max(Positions))]
[groups[Positions[i]-1].append(Heat[i]) for i in range(len(Heat))];
b = plt.boxplot(groups, patch_artist=False);
plt.rcParams.update({'font.size': 16})
plt.rc ('xtick', labelsize=16)
plt.rc ('ytick', labelsize=18)
for median in b['medians']:
median.set(color = 'r', linewidth = 2)
I can get the following box plot but I want the numbers 1...5 to be replaced by A...E? Is there an alternative way I can do this?
To convert a char to an integer, use
ord(char)
To convert an integer to a char, use
chr(int)
An example:
int_array = list(range(5))
char_array = [chr(x + ord('A')) for x in int_array]
# char_array = ['A', 'B', 'C', 'D', 'E']

How do I create an array that repeats every number twice?

I want to create an array with the following structure when printed:
1: (10,20),
2: (20,30),
3: (30,40),
4: (40,50),
and so on...
Really new to python so anything helps! Using python 3.
you can simply do by python range function range(start, end, stepsize)
final_lst = []
for i in range(10, 200, 10):
final_lst.append([i, i+10])
print(final_lst)
output
[[10, 20], [20, 30], [30, 40], [40, 50], [50, 60], [60, 70], [70, 80], [80, 90], [90, 100], [100, 110], [110, 120], [120, 130], [130, 140], [140, 150], [150, 160], [160, 170], [170, 180], [180, 190], [190, 200]]
::edit::
for i in range(1, 10):
print('%s: (%s,%s),'%(i, i*10, (i+1)*10))
output
1: (10,20),
2: (20,30),
3: (30,40),
4: (40,50),
5: (50,60),
6: (60,70),
7: (70,80),
8: (80,90),
9: (90,100),
take two variables cnt1 and cnt2
import numpy as np
myList = []
cnt1=1
cnt2=2
for i in range(n): #n is desired length
myList.append([10*cnt1,10*cnt2])
cnt1+=1
cnt2+=1
myArray = np.array(myList)
You can write a function that uses range to get a range of values and a list comprehension (basically an inline for-loop) to generate a list of tuples. Something like this:
def get_repeated_list(max_n):
values = range(10, max_n, 10)
return [(i, i+10) for i in values]
Example usage:
>>> get_repeated_list(50)
[(10, 20), (20, 30), (30, 40), (40, 50)]
Looks like what you want to do is is transform a list into another list of previous/next elements.
listA = [ 10 * i for i in range( N ) ]
listB = [ (listA[ i ], listA[ i + 1 ]) for i in range( len( listA ) - 1 ) ];
Let l be your list. It doesn't matter what is in it. Use zip to make a new list, with wanted feature. zip, matches elements of two list together. if you zip a list with itself, you'll have a new list that each element in first list is repeated twice in it.
l = [1, 2, 5, 11, 12]
for element in zip(l, l):
print(element)
output:
(1, 1)
(2, 2)
(5, 5)
(11, 11)
(12, 12)

Multiply each row of one array with each element of another array in numpy

I have two arrays A and B in numpy. A holds cartesian coordinates, each row is one point in 3D space and has the shape (r, 3). B has the shape (r, n) and holds integers.
What I would like to do is multiply each element of B with each row in A, so that the resulting array has the shape (r, n, 3). So for example:
# r = 3
A = np.array([1,1,1, 2,2,2, 3,3,3]).reshape(3,3)
# n = 2
B = np.array([10, 20, 30, 40, 50, 60]).reshape(3,2)
# Result with shape (3, 2, 3):
# [[[10,10,10], [20,20,20]],
# [[60,60,60], [80,80,80]]
# [[150,150,150], [180,180,180]]]
I'm pretty sure this can be done with np.einsum, but I've been trying this for quite a while now and can't get it to work.
Use broadcasting -
A[:,None,:]*B[:,:,None]
Since np.einsum also supports broadcasting, you can use that as well (thanks to #ajcr for suggesting this concise version) -
np.einsum('ij,ik->ikj',A,B)
Sample run -
In [22]: A
Out[22]:
array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])
In [23]: B
Out[23]:
array([[10, 20],
[30, 40],
[50, 60]])
In [24]: A[:,None,:]*B[:,:,None]
Out[24]:
array([[[ 10, 10, 10],
[ 20, 20, 20]],
[[ 60, 60, 60],
[ 80, 80, 80]],
[[150, 150, 150],
[180, 180, 180]]])
In [25]: np.einsum('ijk,ij->ijk',A[:,None,:],B)
Out[25]:
array([[[ 10, 10, 10],
[ 20, 20, 20]],
[[ 60, 60, 60],
[ 80, 80, 80]],
[[150, 150, 150],
[180, 180, 180]]])

Categories

Resources