@@ -583,7 +583,33 @@ cdef class Array:
583
583
return r
584
584
585
585
def resize (self , *args ):
586
- """ TODO"""
586
+ """ Resize the array by growing or shrinking one or more dimensions.
587
+
588
+ Parameters
589
+ ----------
590
+ args : int or sequence of ints
591
+ New shape to resize to.
592
+
593
+ Notes
594
+ -----
595
+ This function can only be used to change the size of existing
596
+ dimensions, it cannot add or drop dimensions.
597
+
598
+ N.B., this function does *not* behave in the same way as the numpy
599
+ resize method on the ndarray class. Existing data are *not*
600
+ reorganised in any way. Axes are simply grown or shrunk. When
601
+ growing an axis, uninitialised portions of the array will appear to
602
+ contain the value of the `fill_value` attribute on this array,
603
+ and when shrinking an array any data beyond the new shape will be
604
+ lost (although see note below).
605
+
606
+ N.B., because of the way the underlying chunks are organised,
607
+ and in particular the fact that chunks may overhang the edge of the
608
+ array, the value of uninitialised portions of this array is not
609
+ guaranteed to respect the setting of the `fill_value` attribute when
610
+ shrinking then regrowing an array.
611
+
612
+ """
587
613
588
614
# normalise new shape argument
589
615
if len (args) == 1 :
@@ -601,15 +627,24 @@ cdef class Array:
601
627
new_shape = tuple (s if n is None else n
602
628
for s, n in zip (self .shape, new_shape))
603
629
604
- # set new shape
605
- self .shape = new_shape
630
+ # work-around Cython problems with accessing .shape attribute as tuple
631
+ old_cdata = np.asarray(self .cdata)
632
+
633
+ # remember old cdata shape
634
+ old_cdata_shape = old_cdata.shape
606
635
607
636
# determine the new number and arrangement of chunks
608
637
new_cdata_shape = tuple (int (np.ceil(s / c))
609
638
for s, c in zip (new_shape, self .chunks))
610
639
611
- # resize chunks array
612
- self .cdata.resize(new_cdata_shape, refcheck = False )
640
+ # setup new chunks array
641
+ new_cdata = np.empty(new_cdata_shape, dtype = object )
642
+
643
+ # copy across any chunks to be kept
644
+ cdata_overlap = tuple (
645
+ slice (min (o, n)) for o, n in zip (old_cdata_shape, new_cdata_shape)
646
+ )
647
+ new_cdata[cdata_overlap] = old_cdata[cdata_overlap]
613
648
614
649
# determine function for instantiating chunks
615
650
if self .synchronized:
@@ -618,33 +653,64 @@ cdef class Array:
618
653
create_chunk = Chunk
619
654
620
655
# instantiate any new chunks as needed
621
- self .cdata .flat = [create_chunk(self .chunks, dtype = self .dtype,
622
- cname = self .cname,
623
- clevel = self .clevel,
624
- shuffle = self .shuffle,
625
- fill_value = self .fill_value)
626
- if c == 0 else c
627
- for c in self .cdata .flat]
656
+ new_cdata .flat = [create_chunk(self .chunks, dtype = self .dtype,
657
+ cname = self .cname,
658
+ clevel = self .clevel,
659
+ shuffle = self .shuffle,
660
+ fill_value = self .fill_value)
661
+ if c is None else c
662
+ for c in new_cdata .flat]
628
663
629
- def append (self , data ):
630
- """ TODO"""
664
+ # set new shape
665
+ self .shape = new_shape
666
+
667
+ # set new chunks
668
+ self .cdata = new_cdata
669
+
670
+ def append (self , data , axis = 0 ):
671
+ """ Append `data` to `axis`.
672
+
673
+ Parameters
674
+ ----------
675
+ data : array_like
676
+ Data to be appended.
677
+ axis : int
678
+ Axis along which to append.
679
+
680
+ Notes
681
+ -----
682
+ The size of all dimensions other than `axis` must match between this
683
+ array and `data`.
684
+
685
+ """
631
686
632
687
# ensure data is array-like
633
688
if not hasattr (data, ' shape' ) or not hasattr (data, ' dtype' ):
634
689
data = np.asanyarray(data)
635
690
636
- # ensure shapes are compatible for trailing dimensions
637
- if self .shape[1 :] != data.shape[1 :]:
638
- raise ValueError (' shape not compatible' )
691
+ # ensure shapes are compatible for non-append dimensions
692
+ self_shape_preserved = tuple (s for i, s in enumerate (self .shape)
693
+ if i != axis)
694
+ data_shape_preserved = tuple (s for i, s in enumerate (data.shape)
695
+ if i != axis)
696
+ if self_shape_preserved != data_shape_preserved:
697
+ raise ValueError (' shapes not compatible' )
639
698
640
699
# remember old shape
641
700
old_shape = self .shape
642
701
643
702
# determine new shape
644
- new_shape = (self .shape[0 ] + data.shape[0 ],) + self .shape[1 :]
703
+ new_shape = tuple (
704
+ self .shape[i] if i != axis else self .shape[i] + data.shape[i]
705
+ for i in range (len (self .shape))
706
+ )
645
707
646
708
# resize
647
709
self .resize(new_shape)
648
710
649
711
# store data
650
- self [old_shape[0 ]:] = data
712
+ append_selection = tuple (
713
+ slice (None ) if i != axis else slice (old_shape[i], new_shape[i])
714
+ for i in range (len (self .shape))
715
+ )
716
+ self [append_selection] = data
0 commit comments