554554</ a >
555555</ li >
556556< li class ="md-nav__item ">
557+ < a class ="md-nav__link " href ="#plugin-codecs ">
558+ < span class ="md-ellipsis ">
559+
560+ Plugin Codecs
561+
562+ </ span >
563+ </ a >
564+ </ li >
565+ < li class ="md-nav__item ">
557566< a class ="md-nav__link " href ="#blob-serialized-python-objects ">
558567< span class ="md-ellipsis ">
559568
572581</ a >
573582</ li >
574583< li class ="md-nav__item ">
584+ < a class ="md-nav__link " href ="#npy-numpy-arrays-as-npy-files ">
585+ < span class ="md-ellipsis ">
586+
587+ <npy@> — NumPy Arrays as .npy Files
588+
589+ </ span >
590+ </ a >
591+ </ li >
592+ < li class ="md-nav__item ">
575593< a class ="md-nav__link " href ="#object-path-addressed-storage ">
576594< span class ="md-ellipsis ">
577595
23942412</ a >
23952413</ li >
23962414< li class ="md-nav__item ">
2415+ < a class ="md-nav__link " href ="#plugin-codecs ">
2416+ < span class ="md-ellipsis ">
2417+
2418+ Plugin Codecs
2419+
2420+ </ span >
2421+ </ a >
2422+ </ li >
2423+ < li class ="md-nav__item ">
23972424< a class ="md-nav__link " href ="#blob-serialized-python-objects ">
23982425< span class ="md-ellipsis ">
23992426
24122439</ a >
24132440</ li >
24142441< li class ="md-nav__item ">
2442+ < a class ="md-nav__link " href ="#npy-numpy-arrays-as-npy-files ">
2443+ < span class ="md-ellipsis ">
2444+
2445+ <npy@> — NumPy Arrays as .npy Files
2446+
2447+ </ span >
2448+ </ a >
2449+ </ li >
2450+ < li class ="md-nav__item ">
24152451< a class ="md-nav__link " href ="#object-path-addressed-storage ">
24162452< span class ="md-ellipsis ">
24172453
@@ -2487,6 +2523,7 @@ <h2 id="three-layer-architecture">Three-Layer Architecture<a class="headerlink"
24872523 subgraph "Layer 3: Codecs"
24882524 blob["‹blob›"]
24892525 attach["‹attach›"]
2526+ npy["‹npy@›"]
24902527 object["‹object@›"]
24912528 hash["‹hash@›"]
24922529 custom["‹custom›"]
@@ -2508,6 +2545,7 @@ <h2 id="three-layer-architecture">Three-Layer Architecture<a class="headerlink"
25082545
25092546 blob --> bytes
25102547 attach --> bytes
2548+ npy --> json
25112549 object --> json
25122550 hash --> json
25132551 bytes --> BLOB
@@ -2663,6 +2701,12 @@ <h3 id="built-in-codecs">Built-in Codecs<a class="headerlink" href="#built-in-co
26632701< td > Local file path</ td >
26642702</ tr >
26652703< tr >
2704+ < td > < code > <npy@></ code > </ td >
2705+ < td > ❌</ td >
2706+ < td > ✅</ td >
2707+ < td > NpyRef (lazy)</ td >
2708+ </ tr >
2709+ < tr >
26662710< td > < code > <object@></ code > </ td >
26672711< td > ❌</ td >
26682712< td > ✅</ td >
@@ -2682,6 +2726,58 @@ <h3 id="built-in-codecs">Built-in Codecs<a class="headerlink" href="#built-in-co
26822726</ tr >
26832727</ tbody >
26842728</ table >
2729+ < h3 id ="plugin-codecs "> Plugin Codecs< a class ="headerlink " href ="#plugin-codecs " title ="Permanent link "> ¶</ a > </ h3 >
2730+ < p > Additional codecs are available as separately installed packages. This ecosystem is actively expanding—new codecs are added as community needs arise.</ p >
2731+ < table >
2732+ < thead >
2733+ < tr >
2734+ < th > Package</ th >
2735+ < th > Codec</ th >
2736+ < th > Description</ th >
2737+ < th > Repository</ th >
2738+ </ tr >
2739+ </ thead >
2740+ < tbody >
2741+ < tr >
2742+ < td > < code > dj-zarr-codecs</ code > </ td >
2743+ < td > < code > <zarr@></ code > </ td >
2744+ < td > Zarr arrays with lazy chunked access</ td >
2745+ < td > < a href ="https://github.com/datajoint/dj-zarr-codecs "> datajoint/dj-zarr-codecs</ a > </ td >
2746+ </ tr >
2747+ < tr >
2748+ < td > < code > dj-figpack-codecs</ code > </ td >
2749+ < td > < code > <figpack@></ code > </ td >
2750+ < td > Interactive browser visualizations</ td >
2751+ < td > < a href ="https://github.com/datajoint/dj-figpack-codecs "> datajoint/dj-figpack-codecs</ a > </ td >
2752+ </ tr >
2753+ < tr >
2754+ < td > < code > dj-photon-codecs</ code > </ td >
2755+ < td > < code > <photon@></ code > </ td >
2756+ < td > Photon imaging data formats</ td >
2757+ < td > < a href ="https://github.com/datajoint/dj-photon-codecs "> datajoint/dj-photon-codecs</ a > </ td >
2758+ </ tr >
2759+ </ tbody >
2760+ </ table >
2761+ < p > < strong > Installation and discovery:</ strong > </ p >
2762+ < p > Plugin codecs use Python's entry point mechanism for automatic registration. Install the package and DataJoint discovers the codec automatically:</ p >
2763+ < div class ="highlight "> < pre > < span > </ span > < code > pip< span class ="w "> </ span > install< span class ="w "> </ span > dj-zarr-codecs
2764+ </ code > </ pre > </ div >
2765+ < div class ="highlight "> < pre > < span > </ span > < code > < span class ="kn "> import</ span > < span class ="w "> </ span > < span class ="nn "> datajoint</ span > < span class ="w "> </ span > < span class ="k "> as</ span > < span class ="w "> </ span > < span class ="nn "> dj</ span >
2766+
2767+ < span class ="c1 "> # Codec is available immediately after install</ span >
2768+ < span class ="nd "> @schema</ span >
2769+ < span class ="k "> class</ span > < span class ="w "> </ span > < span class ="nc "> Analysis</ span > < span class ="p "> (</ span > < span class ="n "> dj</ span > < span class ="o "> .</ span > < span class ="n "> Computed</ span > < span class ="p "> ):</ span >
2770+ < span class ="n "> definition</ span > < span class ="o "> =</ span > < span class ="s2 "> """</ span >
2771+ < span class ="s2 "> -> Recording</ span >
2772+ < span class ="s2 "> ---</ span >
2773+ < span class ="s2 "> data : <zarr@store></ span >
2774+ < span class ="s2 "> """</ span >
2775+ </ code > </ pre > </ div >
2776+ < p > Packages declare their codecs in < code > pyproject.toml</ code > under the < code > datajoint.codecs</ code > entry point group:</ p >
2777+ < div class ="highlight "> < pre > < span > </ span > < code > < span class ="k "> [project.entry-points.</ span > < span class ="s2 "> "datajoint.codecs"</ span > < span class ="k "> ]</ span >
2778+ < span class ="n "> zarr</ span > < span class ="w "> </ span > < span class ="o "> =</ span > < span class ="w "> </ span > < span class ="s2 "> "dj_zarr_codecs:ZarrCodec"</ span >
2779+ </ code > </ pre > </ div >
2780+ < p > DataJoint loads these entry points on first use, making third-party codecs indistinguishable from built-ins.</ p >
26852781< h3 id ="blob-serialized-python-objects "> < code > <blob></ code > — Serialized Python Objects< a class ="headerlink " href ="#blob-serialized-python-objects " title ="Permanent link "> ¶</ a > </ h3 >
26862782< p > Stores NumPy arrays, dicts, lists, and other Python objects using DataJoint's custom binary serialization format.</ p >
26872783< p > < strong > Serialization format:</ strong > </ p >
@@ -2727,6 +2823,34 @@ <h3 id="attach-file-attachments"><code><attach></code> — File Attachment
27272823< span class ="s2 "> data_file : <attach@> # Large file in object store</ span >
27282824< span class ="s2 "> """</ span >
27292825</ code > </ pre > </ div >
2826+ < h3 id ="npy-numpy-arrays-as-npy-files "> < code > <npy@></ code > — NumPy Arrays as .npy Files< a class ="headerlink " href ="#npy-numpy-arrays-as-npy-files " title ="Permanent link "> ¶</ a > </ h3 >
2827+ < p > Stores NumPy arrays as standard < code > .npy</ code > files with lazy loading. Returns < code > NpyRef</ code > which provides metadata access (shape, dtype) without downloading.</ p >
2828+ < div class ="highlight "> < pre > < span > </ span > < code > < span class ="k "> class</ span > < span class ="w "> </ span > < span class ="nc "> Recording</ span > < span class ="p "> (</ span > < span class ="n "> dj</ span > < span class ="o "> .</ span > < span class ="n "> Computed</ span > < span class ="p "> ):</ span >
2829+ < span class ="n "> definition</ span > < span class ="o "> =</ span > < span class ="s2 "> """</ span >
2830+ < span class ="s2 "> -> Session</ span >
2831+ < span class ="s2 "> ---</ span >
2832+ < span class ="s2 "> waveform : <npy@> # Default store</ span >
2833+ < span class ="s2 "> spectrogram : <npy@archive> # Named store</ span >
2834+ < span class ="s2 "> """</ span >
2835+ </ code > </ pre > </ div >
2836+ < p > < strong > Lazy access:</ strong > </ p >
2837+ < div class ="highlight "> < pre > < span > </ span > < code > < span class ="n "> ref</ span > < span class ="o "> =</ span > < span class ="p "> (</ span > < span class ="n "> Recording</ span > < span class ="o "> &</ span > < span class ="n "> key</ span > < span class ="p "> )</ span > < span class ="o "> .</ span > < span class ="n "> fetch1</ span > < span class ="p "> (</ span > < span class ="s1 "> 'waveform'</ span > < span class ="p "> )</ span >
2838+ < span class ="n "> ref</ span > < span class ="o "> .</ span > < span class ="n "> shape</ span > < span class ="c1 "> # (1000, 32) — no download</ span >
2839+ < span class ="n "> ref</ span > < span class ="o "> .</ span > < span class ="n "> dtype</ span > < span class ="c1 "> # float64 — no download</ span >
2840+
2841+ < span class ="c1 "> # Explicit load</ span >
2842+ < span class ="n "> arr</ span > < span class ="o "> =</ span > < span class ="n "> ref</ span > < span class ="o "> .</ span > < span class ="n "> load</ span > < span class ="p "> ()</ span >
2843+
2844+ < span class ="c1 "> # Transparent numpy integration</ span >
2845+ < span class ="n "> result</ span > < span class ="o "> =</ span > < span class ="n "> np</ span > < span class ="o "> .</ span > < span class ="n "> mean</ span > < span class ="p "> (</ span > < span class ="n "> ref</ span > < span class ="p "> )</ span > < span class ="c1 "> # Downloads automatically</ span >
2846+ </ code > </ pre > </ div >
2847+ < p > < strong > Key features:</ strong > </ p >
2848+ < ul >
2849+ < li > < strong > Portable format</ strong > : Standard < code > .npy</ code > readable by NumPy, MATLAB, etc.</ li >
2850+ < li > < strong > Lazy loading</ strong > : Shape/dtype available without I/O</ li >
2851+ < li > < strong > Safe bulk fetch</ strong > : Fetching many rows doesn't download until needed</ li >
2852+ < li > < strong > Memory mapping</ strong > : < code > ref.load(mmap_mode='r')</ code > for random access to large arrays</ li >
2853+ </ ul >
27302854< h3 id ="object-path-addressed-storage "> < code > <object@></ code > — Path-Addressed Storage< a class ="headerlink " href ="#object-path-addressed-storage " title ="Permanent link "> ¶</ a > </ h3 >
27312855< p > For large/complex file structures (Zarr, HDF5). Path derived from primary key.</ p >
27322856< div class ="highlight "> < pre > < span > </ span > < code > < span class ="k "> class</ span > < span class ="w "> </ span > < span class ="nc "> ProcessedData</ span > < span class ="p "> (</ span > < span class ="n "> dj</ span > < span class ="o "> .</ span > < span class ="n "> Computed</ span > < span class ="p "> ):</ span >
@@ -2829,17 +2953,25 @@ <h2 id="choosing-types">Choosing Types<a class="headerlink" href="#choosing-type
28292953</ tr >
28302954< tr >
28312955< td > NumPy arrays (large)</ td >
2832- < td > < code > <blob@></ code > </ td >
2956+ < td > < code > <npy@> </ code > or < code > < blob@></ code > </ td >
28332957</ tr >
28342958< tr >
28352959< td > Files to attach</ td >
28362960< td > < code > <attach></ code > or < code > <attach@></ code > </ td >
28372961</ tr >
28382962< tr >
2839- < td > Zarr/HDF5</ td >
2963+ < td > Zarr arrays</ td >
2964+ < td > < code > <zarr@></ code > (plugin)</ td >
2965+ </ tr >
2966+ < tr >
2967+ < td > Complex file structures</ td >
28402968< td > < code > <object@></ code > </ td >
28412969</ tr >
28422970< tr >
2971+ < td > Interactive visualizations</ td >
2972+ < td > < code > <figpack@></ code > (plugin)</ td >
2973+ </ tr >
2974+ < tr >
28432975< td > File references (in-store)</ td >
28442976< td > < code > <filepath@store></ code > </ td >
28452977</ tr >
0 commit comments