collectionView:cellForItemAtIndexPath mixes up images, drawn with drawRect: - drawrect

I decided to draw my UICollectionViewCell's with drawRect: instead of the custom xib files for performance (as I have shadows and label shadows).
For some reason, since I changed this, my cells not draw with different images each time they are reloaded into the UICollectionView.
When I log the name of the image it is set to load in both the collectionView:cellForItemAtIndexPath and drawRect: it supplies the correct name of the image and the correct index path, yet when I load the app, it muddles them up on scrolling, even though initially, they have loaded correctly.
Here is my code:
viewDidLoad
// Collection cells
//
[self.collectionView registerClass:[CluelessSymbolCell class] forCellWithReuseIdentifier:#"Symbol cell"];
collectionView:cellForItemAtIndexPath
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CluelessSymbolCell *cell = (CluelessSymbolCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"Symbol cell" forIndexPath:indexPath];
CluelessClue *clue = [self.clues objectAtIndex:indexPath.row];
NSLog(#"(%#) Image: %#", indexPath, [clue.imageNames objectAtIndex:0]);
[cell setClue:clue];
return cell;
}
drawRect: (In cell subclass 'CluelessSymbolCell')
- (void)drawRect:(CGRect)rect
{
NSString *imageName = [NSString stringWithFormat:#"%#-icon-iphone", [self.clue.imageNames objectAtIndex:0]];
// Cell
//
[self.contentView.layer setShadowColor:[UIColor blackColor].CGColor];
[self.contentView.layer setShadowOpacity:0.3f];
[self.contentView.layer setShadowRadius:2.0f];
[self.contentView.layer setShadowOffset:CGSizeZero];
[self.contentView.layer setShadowPath:[UIBezierPath bezierPathWithRect:self.layer.bounds].CGPath];
// Image
//
CALayer *imageLayer = [CALayer layer];
[imageLayer setFrame:rect];
[imageLayer setContents:(id)[[UIImage imageNamed:imageName] CGImage]];
[self.contentView.layer addSublayer:imageLayer];
}
Edit
On logging the sublayers of the cell's content view, I can see that each cell's contentview sublayer has moved to the next cell, what is the reason for this and how do I overcome it?
Log:
2013-02-22 23:41:08.064 Clueless[3462:c07] <NSIndexPath 0x845cb90> 2 indexes [0, 0], (null)
2013-02-22 23:41:08.065 Clueless[3462:c07] <NSIndexPath 0x84435f0> 2 indexes [0, 1], (null)
2013-02-22 23:41:08.066 Clueless[3462:c07] <NSIndexPath 0x8446f50> 2 indexes [0, 2], (null)
2013-02-22 23:41:08.066 Clueless[3462:c07] <NSIndexPath 0x843a060> 2 indexes [0, 3], (null)
2013-02-22 23:41:08.067 Clueless[3462:c07] <NSIndexPath 0x846bc70> 2 indexes [0, 4], (null)
2013-02-22 23:41:08.067 Clueless[3462:c07] <NSIndexPath 0x845cd20> 2 indexes [0, 5], (null)
2013-02-22 23:41:08.068 Clueless[3462:c07] <NSIndexPath 0x845ce60> 2 indexes [0, 6], (null)
2013-02-22 23:41:08.068 Clueless[3462:c07] <NSIndexPath 0x846ce40> 2 indexes [0, 7], (null)
2013-02-22 23:41:08.069 Clueless[3462:c07] <NSIndexPath 0x846c9b0> 2 indexes [0, 8], (null)
2013-02-22 23:41:08.069 Clueless[3462:c07] <NSIndexPath 0x846d880> 2 indexes [0, 9], (null)
2013-02-22 23:41:08.070 Clueless[3462:c07] <NSIndexPath 0x846db20> 2 indexes [0, 10], (null)
2013-02-22 23:41:08.071 Clueless[3462:c07] <NSIndexPath 0x846df30> 2 indexes [0, 11], (null)
2013-02-22 23:41:15.105 Clueless[3462:c07] <NSIndexPath 0x846ec60> 2 indexes [0, 12], (null)
2013-02-22 23:41:15.106 Clueless[3462:c07] <NSIndexPath 0x846efb0> 2 indexes [0, 13], (null)
2013-02-22 23:41:15.107 Clueless[3462:c07] <NSIndexPath 0x846f6d0> 2 indexes [0, 14], (null)
2013-02-22 23:41:15.753 Clueless[3462:c07] <NSIndexPath 0x82492e0> 2 indexes [0, 15], (
"<CALayer: 0x8495840>"
)
2013-02-22 23:41:15.754 Clueless[3462:c07] <NSIndexPath 0x827f750> 2 indexes [0, 16], (
"<CALayer: 0x8491010>"
)
2013-02-22 23:41:15.754 Clueless[3462:c07] <NSIndexPath 0x827f5c0> 2 indexes [0, 17], (
"<CALayer: 0x8493ef0>"
)
2013-02-22 23:41:15.986 Clueless[3462:c07] <NSIndexPath 0x845cb90> 2 indexes [0, 0], (
"<CALayer: 0x8493ef0>"
)
2013-02-22 23:41:15.987 Clueless[3462:c07] <NSIndexPath 0x84435f0> 2 indexes [0, 1], (
"<CALayer: 0x8491010>"
)
2013-02-22 23:41:15.987 Clueless[3462:c07] <NSIndexPath 0x8446f50> 2 indexes [0, 2], (
"<CALayer: 0x8495840>"
)
2013-02-22 23:41:26.161 Clueless[3462:c07] <NSIndexPath 0x827d970> 2 indexes [0, 12], (
"<CALayer: 0x8241e20>"
)
2013-02-22 23:41:26.162 Clueless[3462:c07] <NSIndexPath 0x824e9d0> 2 indexes [0, 13], (
"<CALayer: 0x827bc60>"
)
2013-02-22 23:41:26.163 Clueless[3462:c07] <NSIndexPath 0x827d030> 2 indexes [0, 14], (
"<CALayer: 0x8242fb0>"
)
2013-02-22 23:41:26.776 Clueless[3462:c07] <NSIndexPath 0x82492e0> 2 indexes [0, 15], (
"<CALayer: 0x8491010>"
)
2013-02-22 23:41:26.777 Clueless[3462:c07] <NSIndexPath 0x827f750> 2 indexes [0, 16], (
"<CALayer: 0x8493ef0>"
)
2013-02-22 23:41:26.778 Clueless[3462:c07] <NSIndexPath 0x827f5c0> 2 indexes [0, 17], (
"<CALayer: 0x8495840>"
)
2013-02-22 23:41:26.926 Clueless[3462:c07] <NSIndexPath 0x845cb90> 2 indexes [0, 0], (
"<CALayer: 0x8495840>"
)
2013-02-22 23:41:26.927 Clueless[3462:c07] <NSIndexPath 0x84435f0> 2 indexes [0, 1], (
"<CALayer: 0x8493ef0>"
)
2013-02-22 23:41:26.928 Clueless[3462:c07] <NSIndexPath 0x8446f50> 2 indexes [0, 2], (
"<CALayer: 0x8491010>"
)

I don't know if it's a bug, or some kind of problem my end.
However, it seems that to overcome this you need to force drawRect: inside prepareForReuse
- (void)prepareForReuse
{
[super prepareForReuse];
[self setNeedsDisplay];
}

Related

How to sum pandas df rows where each cell contains a list?

I'm trying to sum my df's rows as follows,
let's say I have the beneath df (each cell in a row contains a vector/list of the same size!)
In the real problem, I have a large number of columns and it can vary. But I do have a list that contains the names of those columns.
df = pd.DataFrame([
[[1,2,3],[1,2,3],[1,2,3]],
[[1,1,1],[1,1,1],[1,1,1]],
[[2,2,2],[2,2,2],[2,2,2]]
], columns=['a','b','c'])
I'm trying to create a new Column that will contain the sum of all the vectors in every row- as np.array would do! and get this following vectors as a result:
[3,6,9]
[3,3,3]
[6,6,6]
and not like the .sum(axis=1) does..
[1,2,3,1,2,3,1,2,3]
[1,1,1,1,1,1,1,1,1]
[2,2,2,2,2,2,2,2,2]
Can anyone think of an idea, thanks in advance :)
If same lengths of lists create numpy array and sum for improve performance:
df['Sum'] = np.array(df.to_numpy().tolist()).sum(axis=1).tolist()
print (df)
a b c Sum
0 [1, 2, 3] [1, 2, 3] [1, 2, 3] [3, 6, 9]
1 [1, 1, 1] [1, 1, 1] [1, 1, 1] [3, 3, 3]
2 [2, 2, 2] [2, 2, 2] [2, 2, 2] [6, 6, 6]
Another way using pd.Series.explode:
df['sum'] = df.apply(pd.Series.explode).sum(axis=1).groupby(level=0).agg(list)
Output:
a b c sum
0 [1, 2, 3] [1, 2, 3] [1, 2, 3] [3.0, 6.0, 9.0]
1 [1, 1, 1] [1, 1, 1] [1, 1, 1] [3.0, 3.0, 3.0]
2 [2, 2, 2] [2, 2, 2] [2, 2, 2] [6.0, 6.0, 6.0]

Reading values within pandas.groupby

I have a dataframe like below
name item
0 Jack A
1 Sarah B
2 Ross A
3 Sean C
4 Jack C
5 Ross B
What I like to do is to produce a dictionary that connects people to the products they are related to.
{Jack: [1, 0, 1], Sarah: [0, 1, 0], Ross:[1, 1, 0], Sean:[0, 0, 1]}
I feel like this should be done fairly easily using pandas.groupby
I have tried looping through the dataframe, but I have >1E7 entries, and looping does not look very efficient.
Check with crosstab and to_dict
pd.crosstab(df.item,df.name).to_dict('l')
{'Jack': [1, 0, 1], 'Ross': [1, 1, 0], 'Sarah': [0, 1, 0], 'Sean': [0, 0, 1]}
Another interesting option is using str.get_dummies:
# if you need counts
df.set_index('item')['name'].str.get_dummies().sum(level=0).to_dict('l')
# if you want to record boolean indicators
df.set_index('item')['name'].str.get_dummies().max(level=0).to_dict('l')
# {'Jack': [1, 0, 1], 'Ross': [1, 1, 0], 'Sarah': [0, 1, 0], 'Sean': [0, 0, 1]}

NumPy Convert Elements Across Dimensions

I have 3d numpy array of the following shape:
(3600L, 7200L, 3L)
If any element in any dimension is 0, how can I convert the elements in the same position in other two dimensions into 0?
If an element is 0, it is 0 in each of the dimensions. I'll illustrate with a small 2d array:
In [1240]: M=np.arange(9).reshape(3,3)
In [1241]: M
Out[1241]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [1242]: M[0,0]
Out[1242]: 0
One element is 0, the 0 row and the 0 column. I can set the rest of those 2 dimensions to 0 with:
In [1243]: M[0,:]=0
In [1244]: M[:,0]=0
In [1245]: M
Out[1245]:
array([[0, 0, 0],
[0, 4, 5],
[0, 7, 8]])
You can generalize this to 3d and larger arrays. As long as you know the coordinates of that element in all dimensions. With a 3d array
M[i,:,:]=0
actually sets all the values in a plane (2d) to 0. Similarly for M[:,j,:] and M[:,:,k].
np.where gives the coordinates that match some condition:
In [1248]: I=np.where(M==0)
In [1249]: M[I[0],:]=0
In [1250]: M[:,I[1]]=0
In [1251]: M
Out[1251]:
array([[0, 0, 0],
[0, 4, 5],
[0, 7, 8]])
In [1252]:
In [1252]: I
Out[1252]: (array([0], dtype=int32), array([0], dtype=int32))
This works regardless of whether the match is for 1 element, 0, or more. Here it's just one.

Reduce a dimension of numpy array by selecting

I have a 3d array
A = np.random.random((4,4,3))
and a index matrix
B = np.int_(np.random.random((4,4))*3)
How do I get a 2D array from A based on index matrix B?
In general, how to get a N-1 dimensional array from a ND array and a N-1 dimensional index array?
Lets take an example:
>>> A = np.random.randint(0,10,(3,3,2))
>>> A
array([[[0, 1],
[8, 2],
[6, 4]],
[[1, 0],
[6, 9],
[7, 7]],
[[1, 2],
[2, 2],
[9, 7]]])
Use fancy indexing to take simple indices. Note that the all indices must be of the same shape and the shape of each index will be what is returned.
>>> ind = np.arange(2)
>>> A[ind,ind,ind]
array([0, 9]) #Index (0,0,0) and (1,1,1)
>>> ind = np.arange(2).reshape(2,1)
>>> A[ind,ind,ind]
array([[0],
[9]])
So for your example we need to supply the grid for the first two dimensions:
>>> A = np.random.random((4,4,3))
>>> B = np.int_(np.random.random((4,4))*3)
>>> A
array([[[ 0.95158697, 0.37643036, 0.29175815],
[ 0.84093397, 0.53453123, 0.64183715],
[ 0.31189496, 0.06281937, 0.10008886],
[ 0.79784114, 0.26428462, 0.87899921]],
[[ 0.04498205, 0.63823379, 0.48130828],
[ 0.93302194, 0.91964805, 0.05975115],
[ 0.55686047, 0.02692168, 0.31065731],
[ 0.92822499, 0.74771321, 0.03055592]],
[[ 0.24849139, 0.42819062, 0.14640117],
[ 0.92420031, 0.87483486, 0.51313695],
[ 0.68414428, 0.86867423, 0.96176415],
[ 0.98072548, 0.16939697, 0.19117458]],
[[ 0.71009607, 0.23057644, 0.80725518],
[ 0.01932983, 0.36680718, 0.46692839],
[ 0.51729835, 0.16073775, 0.77768313],
[ 0.8591955 , 0.81561797, 0.90633695]]])
>>> B
array([[1, 2, 0, 0],
[1, 2, 0, 1],
[2, 1, 1, 1],
[1, 2, 1, 2]])
>>> x,y = np.meshgrid(np.arange(A.shape[0]),np.arange(A.shape[1]))
>>> x
array([[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3],
[0, 1, 2, 3]])
>>> y
array([[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3]])
>>> A[x,y,B]
array([[ 0.37643036, 0.48130828, 0.24849139, 0.71009607],
[ 0.53453123, 0.05975115, 0.92420031, 0.36680718],
[ 0.10008886, 0.02692168, 0.86867423, 0.16073775],
[ 0.26428462, 0.03055592, 0.16939697, 0.90633695]])
If you prefer to use mesh as suggested by Daniel, you may also use
A[tuple( np.ogrid[:A.shape[0], :A.shape[1]] + [B] )]
to work with sparse indices. In the general case you could use
A[tuple( np.ogrid[ [slice(0, end) for end in A.shape[:-1]] ] + [B] )]
Note that this may also be used when you'd like to index by B an axis different from the last one (see for example this answer about inserting an element into a list).
Otherwise you can do it using broadcasting:
A[np.arange(A.shape[0])[:, np.newaxis], np.arange(A.shape[1])[np.newaxis, :], B]
This may be generalized too but it's a bit more complicated.

numpy custom array element retrieval

I have a question regarding how to extract certain values from a 2D numpy array
Foo =
array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]])
Bar =
array([[0, 0, 1],
[1, 2, 3]])
I want to extract elements from Foo using the values of Bar as indices, such that I end up with an 2D matrix/array Baz of the same shape as Bar. The ith column in Baz correspond is Foo[(np.array(each j in Bar[:,i]),np.array(i,i,i,i ...))]
Baz =
array([[ 1, 2, 6],
[ 4, 8, 12]])
I could do a couple nested for-loops but I was wondering if there is a more elegant, numpy-ish way to do this.
Sorry if this is a bit convoluted. Let me know if I need to explain further.
Thanks!
You can use Bar as the row index and an array [0, 1, 2] as the column index:
# for easy copy-pasting
import numpy as np
Foo = np.array([[ 1, 2, 3], [ 4, 5, 6], [ 7, 8, 9], [10, 11, 12]])
Bar = np.array([[0, 0, 1], [1, 2, 3]])
# now use Bar as the `i` coordinate and 0, 1, 2 as the `j` coordinate:
Foo[Bar, [0, 1, 2]]
# array([[ 1, 2, 6],
# [ 4, 8, 12]])
# OR, to automatically generate the [0, 1, 2]
Foo[Bar, xrange(Bar.shape[1])]