from jyquickhelper import add_notebook_menu
add_notebook_menu()

%matplotlib inline

"""
Explanation: 2A.i - Huge datasets, datasets hiérarchiques
L'exemple Building a huge numpy array using pytables montre créer une grande matrice qui ne tient pourtant pas en mémoire. Il existe des modules qui permet de faire des calcul à partir de données stockées sur disque comme si elles étaient en mémoire.
End of explanation
"""


import h5py
import random
hf = h5py.File('example.hdf5','w')
arr = [ random.randint(0,100) for h in range(0,1000) ]
hf["random/f0_100"] = arr
arr = [ random.randint(0,1000) for h in range(0,10000) ]
hf["random/f0_1000"] = arr
hf.close()

hf = h5py.File('example.hdf5','r')
print(hf)
for k in hf :
    for k2 in hf[k] :
        obj =hf["{0}/{1}".format(k,k2)]
        print(k, k2, obj, obj.value.shape)
hf.close()

"""
Explanation: h5py
Le module h5py est un module qui permet d'agréger un grand nombre de données dans un seul fichier et de les nommer comme des fichiers sur un disque. L'exemple suivant crée un seul fichier contenant deux tableaux :
End of explanation
"""


hf = h5py.File('example.hdf5','r')
print(hf["random/f0_1000"][20:25])
hf.close()

"""
Explanation: L'avantage est de pouvoir accéder à une partie d'un ensemble sans que celui-ci ne soit chargé en mémoire :
End of explanation
"""


try:
    from tables import IsDescription, StringCol, Int64Col, Float32Col, Float64Col
except ImportError as e:
    # Parfois cela échoue sur Windows: DLL load failed: La procédure spécifiée est introuvable.
    import sys
    raise ImportError("Cannot import tables.\n" + "\n".join(sys.path)) from e

class Particle(IsDescription):
    name      = StringCol(16)   # 16-character String
    idnumber  = Int64Col()      # Signed 64-bit integer
    pressure  = Float32Col()    # float  (single-precision)
    energy    = Float64Col()    # double (double-precision)

from tables import open_file

h5file = open_file("particule2.h5", mode = "w", title = "Test file")

group = h5file.create_group("/", 'detector', 'Detector information')
table = h5file.create_table(group, 'readout', Particle, "Readout example")
h5file

particle = table.row

for i in range(10):
    particle['name']  = 'Particle: %6d' % (i)
    particle['pressure'] = float(i*i)
    particle['energy'] = float(particle['pressure'] ** 4)
    particle['idnumber'] = i * (2 ** 34)
    # Insert a new particle record
    particle.append()

table.flush()

table_read = h5file.root.detector.readout
pressure = [x['pressure'] for x in table_read.iterrows() if 20 <= x['pressure'] < 50]
pressure

names = [ x['name'] for x in table.where("""(20 <= pressure) & (pressure < 50)""") ]
names

"""
Explanation: pytables
pytables peut se comprendre comme une sorte de base de données sqlite et sqlite3 qui s'utilise comme un dataframe.
End of explanation
"""


h5file.close()

"""
Explanation: Ces lignes sont extraites du tutoriel. Le module autorise la création de tableaux, toujours sur disque.
End of explanation
"""


import blosc
import numpy as np

a = np.linspace(0, 100, 10000000)
a.shape

packed = blosc.pack_array(a)
type(packed), len(packed)

array = blosc.unpack_array(packed)
type(array)

%timeit blosc.pack_array(a)

%timeit blosc.unpack_array(packed)

"""
Explanation: blosc
blosc compresse des tableaux numérique. Cela permet de libérer de la mémoire pendant le temps qu'il ne sont pas utilisés. Il est optimisé pour perdre le moins de temps possible en compression / décompression.
End of explanation
"""


import time
x = []
t_comp = []
t_dec = []
size = 10
for i in range(1,9):    
    a = np.linspace(0, 100, size)
    t1 = time.perf_counter()
    packed = blosc.pack_array(a)
    t2 = time.perf_counter()
    blosc.unpack_array(packed)
    t3 = time.perf_counter()
    x.append(len(a))
    t_comp.append(t2-t1)
    t_dec.append(t3-t2)
    print(i, t2-t1, t3-t2)
    size *= 10

import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 1)
ax.plot(x, t_comp, label="compression")
ax.plot(x, t_dec, label="décompression")
ax.set_xlabel("taille")
ax.set_ylabel("time(ms)")
ax.set_xscale("log", nonposx='clip')
ax.set_yscale("log", nonposy='clip')
ax.legend();

"""
Explanation: Performance en fonction de la dimension.
End of explanation
"""


