Giter Site home page Giter Site logo

namedarrays.jl's Introduction

NamedArrays

Julia type that implements a drop-in wrapper for AbstractArray type, providing named indices and dimensions.

CI Coverage Status

Idea

We would want to have the possibility to give each row/column/... in an Array names, as well as the array dimensions themselves. This could be used for pretty-printing, indexing, and perhaps even some sort of dimension-checking in certain matrix computations.

In all other respects, a NamedArray should behave the same as the underlying AbstractArray.

A NamedArray should adhere to the interface definition of an AbstractArray itself, if there are cases where this is not true, these should be considered bugs in the implementation of NamedArrays.

Synopsis

julia> using NamedArrays

julia> n = NamedArray(rand(2,4))
2×4 Named Matrix{Float64}
A ╲ B │         1          2          3          4
──────┼───────────────────────────────────────────
10.640719   0.996256   0.534355   0.610259
20.67784   0.281928  0.0112326   0.672123

julia> setnames!(n, ["one", "two"], 1)         # give the names "one" and "two" to the rows (dimension 1)
(OrderedCollections.OrderedDict{Any, Int64}("one" => 1, "two" => 2), OrderedCollections.OrderedDict{Any, Int64}("1" => 1, "2" => 2, "3" => 3, "4" => 4))

julia> n["one", 2:3]
2-element Named Vector{Float64}
B  │
───┼─────────
20.996256
30.534355

julia> n["two", :] = 11:14
11:14

julia> n[Not("two"), :] = 4:7                  # all rows but the one called "two"
4:7

julia> n
2×4 Named Matrix{Float64}
A ╲ B │    1     2     3     4
──────┼───────────────────────
one   │  4.0   5.0   6.0   7.0
two   │ 11.0  12.0  13.0  14.0

julia> sum(n, dims=1)
1×4 Named Matrix{Float64}
 A ╲ B │    1     2     3     4
───────┼───────────────────────
sum(A) │ 15.0  17.0  19.0  21.0

Construction

Default names for indices and dimensions

julia> n = NamedArray([1 2; 3 4]) ## NamedArray(a::Array)
2×2 Named Matrix{Int64}
A ╲ B │ 1  2
──────┼─────
11  2
23  4

n = NamedArray{Int}(2, 2) ## NamedArray{T}(dims...)
2×2 Named Matrix{Int64}
A ╲ B │                 1                  2
──────┼─────────────────────────────────────
133454  72058693549555969
272339073326448640         4318994440

These constructors add default names to the array of type String, "1", "2", ... for each dimension, and names the dimensions :A, :B, ... (which will be all right for 26 dimensions to start with; 26 dimensions should be enough for anyone:-). The former initializes the NamedArray with the Array a, the latter makes an uninitialized NamedArray of element type T with the specified dimensions dims....

Lower level constructors

The key-lookup for names is implemented by using DataStructures.OrderedDicts for each dimension. At a lower level, you can construct NamedArrays this way:

julia> using DataStructures

julia> n = NamedArray([1 3; 2 4], ( OrderedDict("A"=>1, "B"=>2), OrderedDict("C"=>1, "D"=>2) ),
                      ("Rows", "Cols"))
2×2 Named Matrix{Int64}
Rows ╲ Cols │ C  D
────────────┼─────
A           │ 1  3
B           │ 2  4

This is the basic constructor for a NamedArray. The second argument names must be a tuple of OrderedDicts whose range (the values) are exactly covering the range 1:size(a,dim) for each dimension. The keys in the various dictionaries may be of mixed types, but after construction, the type of the names cannot be altered. The third argument dimnames is a tuple of the names of the dimensions themselves, and these names may be of any type.

Vectors of names

# NamedArray{T,N}(a::AbstractArray{T,N}, names::NTuple{N,Vector}, dimnames::NTuple{N})
julia> n = NamedArray([1 3; 2 4], ( ["a", "b"], ["c", "d"] ), ("Rows", "Cols"))
2×2 Named Matrix{Int64}
Rows ╲ Cols │ c  d
────────────┼─────
a           │ 1  3
b           │ 2  4

# NamedArray{T,N}(a::AbstractArray{T,N}, names::NTuple{N,Vector})
julia> n = NamedArray([1 3; 2 4], ( ["a", "b"], ["c", "d"] ))
2×2 Named Matrix{Int64}
A ╲ B │ c  d
──────┼─────
a     │ 1  3
b     │ 2  4

julia> n = NamedArray([1, 2], ( ["a", "b"], ))  # note the comma after ["a", "b"] to ensure evaluation as tuple
2-element Named Vector{Int64}
A  │
───┼──
a  │ 1
b  │ 2

# Names can also be set with keyword arguments
julia> n = NamedArray([1 3; 2 4]; names=( ["a", "b"], ["c", "d"] ), dimnames=("Rows", "Cols"))
2×2 Named Matrix{Int64}
Rows ╲ Cols │ c  d
────────────┼─────
a           │ 1  3
b           │ 2  4

This is a more friendly version of the basic constructor, where the range of the dictionaries is automatically assigned the values 1:size(a, dim) for the names in order. If dimnames is not specified, the default values will be used (:A, :B, etc.).

In principle, there is no limit imposed to the type of the names used, but we discourage the use of Real, AbstractArray and Range, because they have a special interpretation in getindex() and setindex.

Indexing

Integer indices

Single and multiple integer indices work as for the underlying array:

julia> n[1, 1]
1

julia> n[1]
1

Because the constructed NamedArray itself is an AbstractArray, integer indices always have precedence:

julia> a = rand(2, 4)
2×4 Matrix{Float64}:
 0.272237  0.904488  0.847206  0.20988
 0.533134  0.284041  0.370965  0.421939

julia> dodgy = NamedArray(a, ([2, 1], [10, 20, 30, 40]))
2×4 Named Matrix{Float64}
A ╲ B │       10        20        30        40
──────┼───────────────────────────────────────
20.272237  0.904488  0.847206   0.20988
10.533134  0.284041  0.370965  0.421939

julia> dodgy[1, 1] == a[1, 1]
true

julia> dodgy[1, 10] ## BoundsError
ERROR: BoundsError: attempt to access 2×4 Matrix{Float64} at index [1, 10]

In some cases, e.g., with contingency tables, it would be very handy to be able to use named Integer indices. In this case, in order to circumvent the normal AbstractArray interpretation of the index, you can wrap the indexing argument in the type Name()

julia> dodgy[Name(1), Name(30)] == a[2, 3] ## true
true

Named indices

julia> n = NamedArray([1 2 3; 4 5 6], (["one", "two"], [:a, :b, :c]))
2×3 Named Matrix{Int64}
A ╲ B │ a  b  c
──────┼────────
one   │ 1  2  3
two   │ 4  5  6


julia> n["one", :a] == 1
true

julia> n[:, :b] == [2, 5]
true

julia> n["two", [1, 3]] == [4, 6]
true

julia> n["one", [:a, :b]] == [1, 2]
true

This is the main use of NamedArrays. Names (keys) and arrays of names can be specified as an index, and these can be mixed with other forms of indexing.

Slices

The example above just shows how the indexing works for the values, but there is a slight subtlety in how the return type of slices is determined

When a single element is selected by an index expression, a scalar value is returned. When an array slice is selected, an attempt is made to return a NamedArray with the correct names for the dimensions.

julia> n[:, :b] ## this expression drops the singleton dimensions, and hence the names
2-element Named Vector{Int64}
A   │
────┼──
one │ 2
two │ 5

julia> n[["one"], [:a]] ## this expression keeps the names
1×1 Named Matrix{Int64}
A ╲ B │ a
──────┼──
one   │ 1

Negation / complement

There is a special type constructor Not(), whose function is to specify which elements to exclude from the array. This is similar to negative indices in the language R. The elements in Not(elements...) select all but the indicated elements from the array.

julia> n[Not(1), :] == n[[2], :] ## note that `n` stays 2-dimensional
true

julia> n[2, Not(:a)] == n[2, [:b, :c]]
true

julia> dodgy[1, Not(Name(30))] == dodgy[1, [1, 2, 4]]
true

Both integers and names can be negated.

Dictionary-style indexing

You can also use a dictionary-style indexing, if you don't want to bother about the order of the dimensions, or make a slice using a specific named dimension:

julia> n[:A => "one"] == [1, 2, 3]
true

julia> n[:B => :c, :A => "two"] == 6
true

julia> n[:A=>:, :B=>:c] == [3, 6]
true

julia> n[:B=>[:a, :b]] == [1 2; 4 5]
true

julia> n[:A=>["one", "two"], :B=>:a] == [1, 4]
true

julia> n[:A=>[1, 2], :B=>:a] == [1, 4]
true

julia> n[:A=>["one"], :B=>1:2] == [1 2]
true

julia> n[:A=>["three"]] # Throws ArgumentError when trying to access non-existent dimension.
ERROR: ArgumentError: Elements for A => ["three"] not found.

Assignment

Most index types can be used for assignment as LHS

julia> n[1, 1] = 0
0

julia> n["one", :b] = 1
1

julia> n[:, :c] = 101:102
101:102

julia> n[:B=>:b, :A=>"two"] = 50
50

julia> n
2×3 Named Matrix{Int64}
A ╲ B │   a    b    c
──────┼──────────────
one   │   0    1  101
two   │   4   50  102

General functions

Access to the names of the indices and dimensions

julia> names(n::NamedArray) ## get all index names for all dimensions
2-element Vector{Vector}:
 ["one", "two"]
 [:a, :b, :c]

julia> names(n::NamedArray, 1) ## just for dimension `1`
2-element Vector{String}:
 "one"
 "two"

julia> dimnames(n::NamedArray) ## the names of the dimensions
2-element Vector{Symbol}:
 :A
 :B

Setting the names after construction

Because the type of the keys are encoded in the type of the NamedArray, you can only change the names of indices if they have the same type as before.

 setnames!(n::NamedArray, names::Vector, dim::Integer)
 setnames!(n::NamedArray, name, dim::Int, index:Integer)
 setdimnames!(n::NamedArray, name, dim:Integer)

sets all the names of dimension dim, or only the name at index index, or the name of the dimension dim.

Enameration

Similar to the iterator enumerate this package provides an enamerate function for iterating simultaneously over both names and values.

enamerate(a::NamedArray)

For example:

julia> n = NamedArray([1 2 3; 4 5 6], (["one", "two"], [:a, :b, :c]))
2×3 Named Matrix{Int64}
A ╲ B │ a  b  c
──────┼────────
one   │ 1  2  3
two   │ 4  5  6

julia> for (name, val) in enamerate(n)
           println("$name ==  $val")
       end
("one", :a) ==  1
("two", :a) ==  4
("one", :b) ==  2
("two", :b) ==  5
("one", :c) ==  3
("two", :c) ==  6

Aggregating functions

Some functions, when operated on a NamedArray, will a name for the singleton index:

julia> sum(n, dims=1)
1×3 Named Matrix{Int64}
 A ╲ B │ a  b  c
───────┼────────
sum(A) │ 5  7  9

julia> prod(n, dims=2)
2×1 Named Matrix{Int64}
A ╲ B │ prod(B)
──────┼────────
one   │       6
two   │     120

Aggregating functions are `sum`, `prod`, `maximum`,  `minimum`,  `mean`,  `std`.

### Convert

```julia
convert(::Type{Array}, a::NamedArray)

converts a NamedArray to an Array by dropping all name information. You can also directly access the underlying array using n.array, or use the accessor function array(n).

Methods with special treatment of names / dimnames

Concatenation

If the names are identical for the relevant dimension, these are retained in the results. Otherwise, the names are reinitialized to the default "1", "2", ...

In the concatenated direction, the names are always re-initialized. This may change is people find we should put more effort to check the concatenated names for uniqueness, and keep original names if that is the case.

julia> hcat(n, n)
2×6 Named Matrix{Int64}
A ╲ hcat │ 1  2  3  4  5  6
─────────┼─────────────────
one      │ 1  2  3  1  2  3
two      │ 4  5  6  4  5  6

julia> vcat(n, n)
4×3 Named Matrix{Int64}
vcat ╲ B │ a  b  c
─────────┼────────
11  2  3
24  5  6
31  2  3
44  5  6

Transposition

julia> n'
3×2 Named LinearAlgebra.Adjoint{Int64, Matrix{Int64}}
B ╲ A │ one  two
──────┼─────────
a     │   1    4
b     │   2    5
c     │   3    6

julia> circshift(n, (1, 2))
2×3 Named Matrix{Int64}
A ╲ B │ b  c  a
──────┼────────
two   │ 5  6  4
one   │ 2  3  1

Similar functions: adjoint, transpose, permutedims operate on the dimnames as well.

julia> rotl90(n)
3×2 Named Matrix{Int64}
B ╲ A │ one  two
──────┼─────────
c     │   3    6
b     │   2    5
a     │   1    4

julia> rotr90(n)
3×2 Named Matrix{Int64}
B ╲ A │ two  one
──────┼─────────
a     │   4    1
b     │   5    2
c     │   6    3

Reordering of dimensions in NamedVectors

julia> v = NamedArray([1, 2, 3], ["a", "b", "c"])
3-element Named Vector{Int64}
A  │
───┼──
a  │ 1
b  │ 2
c  │ 3

julia> Combinatorics.nthperm(v, 4)
3-element Named Vector{Int64}
A  │
───┼──
b  │ 2
c  │ 3
a  │ 1

julia> Random.shuffle(v)
3-element Named Vector{Int64}
A  │
───┼──
b  │ 2
a  │ 1
c  │ 3

julia> reverse(v)
3-element Named Vector{Int64}
A  │
───┼──
c  │ 3
b  │ 2
a  │ 1

julia> sort(1 ./ v)
3-element Named Vector{Float64}
A  │
───┼─────────
c  │ 0.333333
b  │      0.5
a  │      1.0

operate on the names of the rows as well

Broadcasts

In broadcasting, the names of the first argument are kept

julia> ni = NamedArray(1 ./ n.array)
2×3 Named Matrix{Float64}
A ╲ B │        1         2         3
──────┼─────────────────────────────
11.0       0.5  0.333333
20.25       0.2  0.166667

julia> n .+ ni
┌ Warning: Using names of left argument
└ @ NamedArrays ~/werk/julia/NamedArrays.jl/src/arithmetic.jl:25
2×3 Named Matrix{Float64}
A ╲ B │       a        b        c
──────┼──────────────────────────
one   │     2.0      2.5  3.33333
two   │    4.25      5.2  6.16667

julia> n .- v'
2×3 Named Matrix{Int64}
A ╲ B │ a  b  c
──────┼────────
one   │ 0  0  0
two   │ 3  3  3

This is implemented through broadcast.

Further Development

The current goal is to reduce complexity of the implementation. Where possible, we want to use more of the Base.AbstractArray implementation.

A longer term goal is to improve type stability, this might have a repercussion to the semantics of some operations.

Related Packages

The Julia ecosystem now has a number of packages implementing the general idea of attaching names to arrays. For some purposes they may be interchangeable. For others, flexibility or speed or support for particular functions may make one preferable.

  • AxisArrays.jl is of comparable age. It attaches a Symbol to each dimension; this is part of the type thus cannot be mutated after creation.

  • DimensionalData.jl, AxisKeys.jl and AxisIndices.jl are, to first approximation, post-Julia 1.0 re-writes of that. DimensionalData.jl similarly builds in dimension names, in AxisKeys.jl they are provided by composition with NamedDims.jl, and AxisIndices.jl does not support them. All allow some form of named indexing but the notation varies.

Packages with some overlap but a different focus include:

  • NamedDims.jl only attaches a name to each dimension, allowing sum(A, dims = :time) and A[time=3] but keeping indices the usual integers.

  • LabelledArrays.jl instead attaches names to individual elements, allowing A.second == A[2].

  • OffsetArrays.jl shifts the indices of an array, allowing say A[-3] to A[3] to be the first & last elements.

namedarrays.jl's People

Contributors

andreasnoack avatar austinprivett avatar connectedsystems avatar davidavdav avatar diegozea avatar dietercastel avatar goggle avatar joelgoop avatar juliatagbot avatar kristofferc avatar mcabbott avatar nalimilan avatar orenbenkiki avatar panlanfeng avatar rodonn avatar scheidan avatar timholy avatar tkelman avatar tomhaber avatar yha avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

namedarrays.jl's Issues

ones(), zeros(), cat() change key type of name dictionary

A very useful package, thanks a lot for your work!

Some functions seem to change the type of the keys of the name dictionaries to Any. For example:

n = NamedArray(rand(2,4))

oo = ones(n)
zz = zeros(n)

nh = hcat(n, n)
nn = cat(2, n, n)

keytype.(n.dicts)               # (String, String)

keytype.(oo.dicts)              # (Any, Any)
keytype.(zz.dicts)              # (Any, Any)

keytype.(nh.dicts)              # (String, String), good!
keytype.(nn.dicts)              # (Any, Any)

Maybe it is related to #58 but I hope it is still useful to report.

As workaround for zeros and ones I use currently this:

0.0*n       # zeros()
(0.0*n + 1) # ones()

Second constructor example in README.md fails with a MethodError

The following example of construction of a NamedArray is given in README.md:

# NamedArray{T}(dims...)
x = NamedArray{Int}(2, 2)

However, when I run this, it fails with a MethodError both for the current version on master and for v0.5.3. The fallback constructor in typedconstructor.jl/constructors.jl does the right thing if it is changed to accept a variable number of arguments

(::Type{NamedArray{T}}){T}(n...) = NamedArray(Array{T}(n...))

I am running Julia 0.5.1.

Julia 0.5' view doesn't support names

julia> mat = NamedArray(rand(1:10,2,3))
2×3 Named Array{Int64,2}
A ╲ B │  1   2   3
──────┼───────────
1     │ 10   5   4
2     │  1  10   2

julia> view(mat, 2, :)
3-element SubArray{Int64,1,NamedArrays.NamedArray{Int64,2,Array{Int64,2},Tuple{DataStructures.OrderedDict{String,Int64},DataStructures.OrderedDict{String,Int64}}},Tuple{Int64,Colon},false}:
  1
 10
  2

julia> view(mat, "2", :)
ERROR: MethodError: no method matching view(::NamedArrays.NamedArray{Int64,2,Array{Int64,2},Tuple{DataStructures.OrderedDict{String,Int64},DataStructures.OrderedDict{String,Int64}}}, ::String, ::Colon)
Closest candidates are:
  view{T,N}(::AbstractArray{T,N}, ::Union{AbstractArray{T,N},Colon,Real}...) at subarray.jl:63
  view{N}(::AbstractArray{T,N}, ::Union{AbstractArray{T,N},Colon,Real}...) at subarray.jl:73
  view(::AbstractArray{T,N}, ::Union{AbstractArray{T,N},Colon,Real}) at subarray.jl:68

Array labels get lost

I'm trying to get my code working with Julia v0.5.0-pre3. Using this version of Julia, NamedArrays is losing names during some calculations. The reproducer below and sample output demonstrate the problem.

https://gist.github.com/chipkent/25a5350a5d68fbf6d9795c598b929911

######## Julia 0.4

julia> versioninfo()
Julia Version 0.4.6
Commit 2e358ce (2016-06-19 17:16 UTC)
Platform Info:
System: Linux (x86_64-unknown-linux-gnu)
CPU: Intel(R) Core(TM) i5-3570K CPU @ 3.40GHz
WORD_SIZE: 64
BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Sandybridge)
LAPACK: libopenblas64_
LIBM: libopenlibm
LLVM: libLLVM-3.3

julia> include("scripts/debug/bug_reproducers/named_array_dropped_labels.jl")
DEBUG: factors 1000x5 Named Array{Float64,2}
Time ╲ Factor │ Factor1 Factor2 Factor3 Factor4 Factor5
──────────────┼──────────────────────────────────────────────────────
Time1 │ 0.682681 0.641864 0.0604407 0.343892 0.272542
Time2 │ 0.85448 0.332101 0.140453 0.306082 0.663562
Time3 │ 0.0672374 0.267711 0.0454517 0.294357 0.749618
Time4 │ 0.518892 0.301079 0.890731 0.662586 0.55996
Time5 │ 0.0769554 0.872269 0.442797 0.15841 0.615252
Time6 │ 0.885494 0.444591 0.788861 0.717947 0.569386
Time7 │ 0.677105 0.137082 0.863631 0.176956 0.166547
Time8 │ 0.148325 0.629093 0.925951 0.913291 0.17828
Time9 │ 0.944075 0.169607 0.19603 0.379889 0.274374
⋮ ⋮ ⋮ ⋮ ⋮ ⋮
Time992 │ 0.693805 0.383296 0.861673 0.908616 0.1875
Time993 │ 0.797499 0.963533 0.423591 0.44484 0.64167
Time994 │ 0.951585 0.969613 0.312815 0.966057 0.124742
Time995 │ 0.852963 0.630625 0.317665 0.0637761 0.972642
Time996 │ 0.753594 0.457059 0.905828 0.604936 0.147711
Time997 │ 0.860515 0.226983 0.221333 0.0654931 0.150316
Time998 │ 0.896473 0.682781 0.0473148 0.190468 0.343856
Time999 │ 0.788534 0.732614 0.80583 0.738317 0.0428651
Time1000 │ 0.154106 0.132844 0.990082 0.731786 0.941636
DEBUG: returns 1000x100 Named Array{Float64,2}
Time ╲ Security │ Sec1 Sec2 … Sec99 Sec100
────────────────┼──────────────────────────────────────────────────────
Time1 │ 0.92638 0.346999 … 0.504168 0.77981
Time2 │ 0.902844 0.856281 0.689131 0.751413
Time3 │ 0.671873 0.418485 0.406949 0.774751
Time4 │ 0.478624 0.661126 0.943033 0.0871396
Time5 │ 0.934416 0.940301 0.686554 0.254314
Time6 │ 0.186957 0.545432 0.373405 0.467161
Time7 │ 0.130868 0.0862504 0.109323 0.0142819
Time8 │ 0.445318 0.688901 0.520623 0.673937
Time9 │ 0.661327 0.36141 0.870884 0.639285
⋮ ⋮ ⋮ ⋱ ⋮ ⋮
Time992 │ 0.0889218 0.937601 0.654347 0.396031
Time993 │ 0.0816654 0.786998 0.671811 0.359932
Time994 │ 0.239004 0.652326 0.766721 0.792293
Time995 │ 0.763325 0.927483 0.182104 0.97115
Time996 │ 0.254187 0.595176 0.309978 0.513739
Time997 │ 0.601996 0.265519 0.324926 0.58877
Time998 │ 0.318751 0.547839 0.938819 0.273577
Time999 │ 0.240346 0.122401 0.662568 0.0681904
Time1000 │ 0.158931 0.286803 … 0.871096 0.561676
DEBUG: ff 5x5 Named Array{Float64,2}
Factor ╲ Factor │ Factor1 Factor2 Factor3 Factor4 Factor5
────────────────┼────────────────────────────────────────────
Factor1 │ 324.788 254.07 253.938 243.756 231.664
Factor2 │ 254.07 344.417 260.806 251.497 240.182
Factor3 │ 253.938 260.806 353.338 257.702 243.31
Factor4 │ 243.756 251.497 257.702 331.22 239.656
Factor5 │ 231.664 240.182 243.31 239.656 311.273
DEBUG: fr 5x100 Named Array{Float64,2}
Factor ╲ Security │ Sec1 Sec2 Sec3 … Sec98 Sec99 Sec100
──────────────────┼────────────────────────────────────────────────────────
Factor1 │ 234.794 253.224 249.112 … 250.32 255.091 252.256
Factor2 │ 248.816 264.046 256.174 256.292 265.516 259.334
Factor3 │ 243.699 264.389 261.629 260.414 268.212 266.447
Factor4 │ 236.634 254.935 257.02 241.381 260.939 256.981
Factor5 │ 229.31 240.06 242.1 … 232.79 252.774 246.607
DEBUG: result 5x100 Named Array{Float64,2}
Factor ╲ Security │ Sec1 Sec2 … Sec99 Sec100
──────────────────┼──────────────────────────────────────────
Factor1 │ 0.164591 0.199913 … 0.169594 0.182313
Factor2 │ 0.241299 0.231476 0.194579 0.168288
Factor3 │ 0.145925 0.195515 0.183738 0.208703
Factor4 │ 0.156689 0.18994 0.200051 0.199727
Factor5 │ 0.193295 0.144762 … 0.238063 0.209805
DEBUG: betas 5x100 Named Array{Float64,2}
Factor ╲ Security │ Sec1 Sec2 … Sec99 Sec100
──────────────────┼──────────────────────────────────────────
Factor1 │ 0.164591 0.199913 … 0.169594 0.182313
Factor2 │ 0.241299 0.231476 0.194579 0.168288
Factor3 │ 0.145925 0.195515 0.183738 0.208703
Factor4 │ 0.156689 0.18994 0.200051 0.199727
Factor5 │ 0.193295 0.144762 … 0.238063 0.209805

######## Julia 0.5

julia> versioninfo()
Julia Version 0.5.0-rc3+0
Commit e6f843b (2016-08-22 23:43 UTC)
Platform Info:
System: Linux (x86_64-unknown-linux-gnu)
CPU: Intel(R) Core(TM) i5-3570K CPU @ 3.40GHz
WORD_SIZE: 64
BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Sandybridge)
LAPACK: libopenblas64_
LIBM: libopenlibm
LLVM: libLLVM-3.7.1 (ORCJIT, ivybridge)

julia> include("scripts/debug/bug_reproducers/named_array_dropped_labels.jl")
INFO: Recompiling stale cache file /cc/home/chip/.julia/lib/v0.5/NamedArrays.ji for module NamedArrays.
DEBUG: factors 1000×5 Named Array{Float64,2}
Time ╲ Factor │ Factor1 Factor2 Factor3 Factor4 Factor5
──────────────┼──────────────────────────────────────────────────────
Time1 │ 0.648349 0.855487 0.722463 0.277658 0.132881
Time2 │ 0.275969 0.627558 0.51212 0.274781 0.267377
Time3 │ 0.24121 0.934418 0.286226 0.234021 0.224865
Time4 │ 0.508534 0.241432 0.905717 0.0400031 0.0506311
Time5 │ 0.373572 0.640741 0.256917 0.552423 0.747057
Time6 │ 0.991241 0.0965737 0.937885 0.235976 0.0370069
Time7 │ 0.775712 0.731374 0.910524 0.340915 0.754739
Time8 │ 0.692795 0.429867 0.600309 0.437293 0.394104
Time9 │ 0.734837 0.560035 0.925546 0.266141 0.336406
⋮ ⋮ ⋮ ⋮ ⋮ ⋮
Time992 │ 0.987371 0.0194012 0.847687 0.952616 0.361282
Time993 │ 0.940804 0.722899 0.330103 0.401003 0.130805
Time994 │ 0.160483 0.802112 0.984304 0.686892 0.224953
Time995 │ 0.553148 0.182517 0.262282 0.365346 0.0556051
Time996 │ 0.797495 0.194863 0.122536 0.606609 0.837744
Time997 │ 0.694519 0.841973 0.472769 0.184475 0.183813
Time998 │ 0.294962 0.153195 0.55467 0.816292 0.565468
Time999 │ 0.174693 0.267737 0.949439 0.427911 0.133258
Time1000 │ 0.204885 0.590186 0.911271 0.434916 0.654768
DEBUG: returns 1000×100 Named Array{Float64,2}
Time ╲ Security │ Sec1 Sec2 … Sec99 Sec100
────────────────┼──────────────────────────────────────────────────────
Time1 │ 0.961094 0.453677 … 0.70159 0.58722
Time2 │ 0.82677 0.948434 0.33833 0.867072
Time3 │ 0.397409 0.289738 0.574056 0.19874
Time4 │ 0.682279 0.111237 0.728677 0.651904
Time5 │ 0.288991 0.755536 0.961669 0.79252
Time6 │ 0.417239 0.248621 0.195145 0.518017
Time7 │ 0.899178 0.528948 0.696381 0.586146
Time8 │ 0.813802 0.203518 0.906128 0.914609
Time9 │ 0.811821 0.304146 0.117954 0.57387
⋮ ⋮ ⋮ ⋱ ⋮ ⋮
Time992 │ 0.22345 0.430742 0.117276 0.767789
Time993 │ 0.94441 0.105519 0.742508 0.638965
Time994 │ 0.972137 0.790848 0.279617 0.26109
Time995 │ 0.613253 0.927934 0.875223 0.801898
Time996 │ 0.851093 0.297009 0.533278 0.418069
Time997 │ 0.929891 0.390823 0.862143 0.852716
Time998 │ 0.483609 0.619753 0.0517902 0.0206416
Time999 │ 0.840487 0.474191 0.316038 0.907091
Time1000 │ 0.523028 0.439595 … 0.968394 0.768594
DEBUG: ff 5×5 Named Array{Float64,2}
A ╲ B │ 1 2 3 4 5
──────┼────────────────────────────────────────────
1 │ 332.503 236.967 250.882 251.18 255.296
2 │ 236.967 319.42 243.482 245.373 249.957
3 │ 250.882 243.482 338.008 250.624 254.066
4 │ 251.18 245.373 250.624 332.022 251.249
5 │ 255.296 249.957 254.066 251.249 341.92
DEBUG: fr 5×100 Named Array{Float64,2}
A ╲ B │ 1 2 3 … 98 99 100
──────┼────────────────────────────────────────────────────────
1 │ 253.242 237.948 251.454 … 256.298 258.981 248.072
2 │ 250.621 236.002 238.929 243.501 248.803 241.593
3 │ 257.734 244.31 251.131 258.019 256.547 248.014
4 │ 253.789 241.661 249.946 259.311 258.438 246.059
5 │ 261.308 249.192 257.263 … 266.681 264.664 255.645
DEBUG: result 5×100 Named Array{Float64,2}
B ╲ B │ 1 2 3 … 98 99 100
──────┼────────────────────────────────────────────────────────────────────
1 │ 0.172268 0.138416 0.207331 … 0.18332 0.212691 0.192143
2 │ 0.211218 0.180836 0.13274 0.106768 0.166369 0.185148
3 │ 0.201161 0.193388 0.184974 0.188608 0.163329 0.169682
4 │ 0.169127 0.177938 0.18796 0.224197 0.201677 0.160905
5 │ 0.207451 0.218805 0.225002 … 0.260134 0.224066 0.224539
DEBUG: betas 5×100 Named Array{Float64,2}
B ╲ B │ 1 2 3 … 98 99 100
──────┼────────────────────────────────────────────────────────────────────
1 │ 0.172268 0.138416 0.207331 … 0.18332 0.212691 0.192143
2 │ 0.211218 0.180836 0.13274 0.106768 0.166369 0.185148
3 │ 0.201161 0.193388 0.184974 0.188608 0.163329 0.169682
4 │ 0.169127 0.177938 0.18796 0.224197 0.201677 0.160905
5 │ 0.207451 0.218805 0.225002 … 0.260134 0.224066 0.224539

Support for Julia-0.7

Hello, I would be interested to know if the maintainers intend to update the Module to support the 0.7 version of Julia, with any help, or if continue to support Julia 0.5 has a clear precedence (in which case I would plan to create a new module directly).

Indexing using Name fails for heterogeneous dimension names

Note the difference between the first example (Int) and the two others (Union{Int,Missing} and Any):

julia> na = NamedArray([1, 0], ([1, 0],), ("A",))
2-element Named Array{Int64,1}
A  │
───┼──
11
00

julia> na[Name(1)]
1

julia> na = NamedArray([1, 0], ([1, missing],), ("A",))
2-element Named Array{Int64,1}
A       │
────────┼──
11
missing0

julia> na[Name(1)]
ERROR: MethodError: no method matching indices(::DataStructures.OrderedDict{Union{Missing, Int64},Int64}, ::Name{Int64})
You may have intended to import Base.indices
Closest candidates are:
  indices(::AbstractDict{K,V<:Integer}, ::Integer) where {K, V<:Integer} at /home/milan/.julia/packages/NamedArrays/ePz5Y/src/index.jl:68
  indices(::AbstractDict{K,V<:Integer}, ::Name{K}) where {K, V<:Integer} at /home/milan/.julia/packages/NamedArrays/ePz5Y/src/index.jl:72
  indices(::AbstractDict{K,V<:Integer}, ::AbstractArray) where {K, V<:Integer} at /home/milan/.julia/packages/NamedArrays/ePz5Y/src/index.jl:85
  ...
Stacktrace:
 [1] (::getfield(NamedArrays, Symbol("##33#34")))(::DataStructures.OrderedDict{Union{Missing, Int64},Int64}, ::Name{Int64}) at /home/milan/.julia/packages/NamedArrays/ePz5Y/src/index.jl:58
 [2] map(::getfield(NamedArrays, Symbol("##33#34")), ::Tuple{DataStructures.OrderedDict{Union{Missing, Int64},Int64}}, ::Tuple{Name{Int64}}) at ./tuple.jl:181
 [3] getindex(::NamedArray{Int64,1,Array{Int64,1},Tuple{DataStructures.OrderedDict{Union{Missing, Int64},Int64}}}, ::Name{Int64}) at /home/milan/.julia/packages/NamedArrays/ePz5Y/src/index.jl:58
 [4] top-level scope at none:0

julia> na = NamedArray([1, 0], ([1, "a"],), ("A",))
2-element Named Array{Int64,1}
A  │
───┼──
11
a  │ 0

julia> na[Name(1)]
ERROR: KeyError: key 1 not found
Stacktrace:
 [1] getindex at /home/milan/.julia/packages/DataStructures/CImpO/src/ordered_dict.jl:362 [inlined]
 [2] indices at /home/milan/.julia/packages/NamedArrays/ePz5Y/src/index.jl:71 [inlined]
 [3] #33 at /home/milan/.julia/packages/NamedArrays/ePz5Y/src/index.jl:58 [inlined]
 [4] map at ./tuple.jl:181 [inlined]
 [5] getindex(::NamedArray{Int64,1,Array{Int64,1},Tuple{DataStructures.OrderedDict{Any,Int64}}}, ::Name{Int64}) at /home/milan/.julia/packages/NamedArrays/ePz5Y/src/index.jl:58
 [6] top-level scope at none:0

EDIT: note that in the last example na[Name("a")] fails while na["a"] works.

In particular, FreqTables needs the Union{T, Missing} case.

OrderedDict for names?

The OrderedDict type from DataStructures.jl might be a nice data structure to hold the names. OrderedDict will soon be based on a speedy implementation by Jeff Bezanson. OrderedSet might also be appropriate.

Customizing dimensions names

First, would like to thank you for this very useful package!

I am mostly working with arrays in three dimensions and would like to change their names, lets say, from A, B, C to i, j, k Would this be possible?

Simplify printing type

I find the current way of printing the full type of the array quite verbose, e.g.:

2x2 NamedArray{Int64,2,Array{Int64,2},Tuple{Dict{ASCIIString,Int64},Dict{Bool,Int64}}}
Species \ LongSepal false true 
setosa              28    22   
versicolor          3     8  

What do you think about printing only the first part of the type? I.e.:

2x2 NamedArray{Int64,2,...}

Sorting erases indices

Hi, I'm not even sure whether sorting used to work but below you see a minimal example where sorting destroys the indices of the A-dimension (same would hold for B).

Cheers

julia> A = NamedArray([3 4; 1 2])
2x2 Named Array{Int64,2}
A ╲ B │ 1 2
──────┼─────
1 │ 3 4
2 │ 1 2

julia> setnames!(A,["asdf","fdsa"],1)
(DataStructures.OrderedDict("asdf"=>1,"fdsa"=>2),DataStructures.OrderedDict("1"=>1,"2"=>2))

julia> setnames!(A,["hhhh","gggg"],2)
(DataStructures.OrderedDict("asdf"=>1,"fdsa"=>2),DataStructures.OrderedDict("hhhh"=>1,"gggg"=>2))

julia> A
2x2 Named Array{Int64,2}
A ╲ B │ hhhh gggg
──────┼───────────
asdf │ 3 4
fdsa │ 1 2

julia> sort(A,1)
2x2 Named Array{Int64,2}
A ╲ B │ hhhh gggg
──────┼───────────
1 │ 1 2
2 │ 3 4

Feature request? Indexing when order of dimensions is not known

Sorry if this isn't the right place to ask about this.

This package is pretty cool, but one thing I couldn't figure out from reading the documentation is if it is possible to index when the order of dimensions is unkown at compile time. For example, say I'm working on a project and I want to set it up as "struc of arrays" rather than "array of strucs". So, I would have several multi-dimensional arrays. I would want to write a library that would let the user define the dimensions of arrays based on their input data. Or, I might want to experiment with different dimension orders. Or, I might just forget if I haven't been working on the project for a while.

So, would it be possbile to make a method with an extra flag or type to signal un-ordered dimensions? It would need to add an intermediate layer to look-up each demension's order, then re-order the indexing conditions. Maybe a macro would be best?

Support 0-dimensional arrays

Named 0-dimensional arrays are certainly not really useful in themselves, but they can arise as special cases of more general functions. For example, I would find it useful for a frequency table with no variables (which would return the number of cases) in FreqTables.jl.

Currently, they are not supported, as the constructor returns the scalar 0:

julia> NamedArray(Array{Int}())
0

According to @which NamedArray(Array{Int}(), (), ()), this is because of a method apparently defined merely to prevent ambiguity warnings. Do you think it would be possible to fix this? At the very least, it should raise an error, instead of an incorrect result.

adding reverse option in the sort function

Hello, Just trying out NamedArrays with FreqTables. It would be great to have "rev" function added into the sort function. Doesn't fully understand how NamesArray works, but would something like this work from what you already have?

function sort(a::NamedVector, rev=false)
i = sortperm(a.array, rev)
return NamedArray(a.array[i], (names(a, 1)[i],), a.dimnames)
end

(Pretty) print arrays with more than 3 dimensions

This probably relates to issue #27 of last month.

This
NamedArray(rand(Int16,2,4,2))
now looks fantastic in pretty printing.

However your fix may have broken the general (non-pretty) printing of >3-dimensional-arrays. So this
NamedArray(rand(Int16,2,4,2,4))
could still be assigned to a variable and sliced within 3 array dimensions, but any printing of more than 3 dimensions is not possible anymore at least on my system.

Specifically I get this error message:

NamedArray(rand(Int16,2,4,2,4))
2x4x2x4 Named Array{Int16,4}
[:, :, C=1, D=1] =
Error showing value of type NamedArrays.NamedArray{Int16,4,Array{Int16,4},Tuple{Dict{ASCIIString,Int64},Dict{ASCIIString,Int64},Dict{ASCIIString,Int64},Dict{ASCIIString,Int64}}}:
ERROR: MethodError: show has no method matching show(::Base.Terminals.TTYTerminal, ::Array{Int16,2}, ::Int64)
Closest candidates are:
show(::IO, ::NamedArrays.NamedArray{T,2,AT,DT}, ::Int64)
show(::IO, ::NamedArrays.NamedArray{T,1,AT,DT}, ::Int64)
show(::IO, ::AbstractArray{T,N})
...
in show at /Users/lh/.julia/v0.4/NamedArrays/src/show.jl:44
in writemime at /Users/lh/.julia/v0.4/NamedArrays/src/show.jl:21
in display at REPL.jl:114
in display at REPL.jl:117
[inlined code] from multimedia.jl:151
in display at multimedia.jl:163
in print_response at REPL.jl:134
in print_response at REPL.jl:121
in anonymous at REPL.jl:624
in run_interface at /Applications/Julia-0.4.6.app/Contents/Resources/julia/lib/julia/sys.dylib
in run_frontend at /Applications/Julia-0.4.6.app/Contents/Resources/julia/lib/julia/sys.dylib
in run_repl at /Applications/Julia-0.4.6.app/Contents/Resources/julia/lib/julia/sys.dylib
in _start at /Applications/Julia-0.4.6.app/Contents/Resources/julia/lib/julia/sys.dylib

"invalid index" error with Float64 key when names type is not Float64

When the type of the names is not Float64 (e.g. Any) but some keys are Float64, indexing does not work. Interestingly, passing the same key as an integer works.

julia> x=NamedArray([1,2,3], ([1.0,"a",2.0],))
3-element Named Array{Int64,1}
A   │ 
────┼──
1.01
a   │ 2
2.03

julia> x[1.0]
ERROR: ArgumentError: invalid index: 1.0
Stacktrace:
 [1] getindex(::NamedArrays.NamedArray{Int64,1,Array{Int64,1},Tuple{DataStructures.OrderedDict{Any,Int64}}}, ::Float64) at /home/milan/.julia/NamedArrays/src/index.jl:31
 [2] macro expansion at ./REPL.jl:97 [inlined]
 [3] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73

julia> x["a"]
2

julia> x[1]
1

This affects FreqTables with Union{Float64,Missing} variables (nalimilan/FreqTables.jl#23).

Switch arguments order for setnames!()

I think it would be much more natural to specify the dimension for which you want to set the names before passing the names themselves. The current order sounds backwards. What do you think?

A method to print all columns

The NamedArray I want to print has five columns. I use “print” function to print it. Only four columns are printed and the middle column is replaced by an ellipsis. Shouldn't there be a way to print all columns?

(Pretty) print arrays with second dimension of size 1

Thank you very much for fixing #32. The following problem is most likely closely related to this.

Printing simple two-dimensional Named Arrays like
NamedArray(rand(Int16,1,2))
NamedArray(rand(Int16,2,1))
works nicely.

However whenever a third or generally higher order dimensions are added, the case of the second dimension having size 1 poses problems. So printing
NamedArray(rand(Int16,1,2,1))
works perfectly, but
NamedArray(rand(Int16,2,1,1))
does not.

In fact, the error message looks similar to #32 :

NamedArray(rand(Int16,2,1,1))
2x1x1 Named Array{Int16,3}
[:, :, C=1] =
Error showing value of type NamedArrays.NamedArray{Int16,3,Array{Int16,3},Tuple{DataStructures.OrderedDict{ASCIIString,Int64},DataStructures.OrderedDict{ASCIIString,Int64},DataStructures.OrderedDict{ASCIIString,Int64}}}:
ERROR: MethodError: show has no method matching show(::Base.Terminals.TTYTerminal, ::Array{Int16,2}, ::Int64)
Closest candidates are:
show(::IO, ::NamedArrays.NamedArray{T,2,AT,DT}, ::Int64)
show(::IO, ::NamedArrays.NamedArray{T,1,AT,DT}, ::Int64)
show(::IO, ::AbstractArray{T,N})
...
in show at /Users/lh/.julia/v0.4/NamedArrays/src/show.jl:44
in writemime at /Users/lh/.julia/v0.4/NamedArrays/src/show.jl:21
in display at REPL.jl:114
in display at REPL.jl:117
[inlined code] from multimedia.jl:151
in display at multimedia.jl:163
in print_response at REPL.jl:134
in print_response at REPL.jl:121
in anonymous at REPL.jl:624
in run_interface at /Applications/Julia-0.4.6.app/Contents/Resources/julia/lib/julia/sys.dylib
in run_frontend at /Applications/Julia-0.4.6.app/Contents/Resources/julia/lib/julia/sys.dylib
in run_repl at /Applications/Julia-0.4.6.app/Contents/Resources/julia/lib/julia/sys.dylib
in _start at /Applications/Julia-0.4.6.app/Contents/Resources/julia/lib/julia/sys.dylib

Convert method does not work with integer names

The following causes a KeyError:

using NamedArrays
x = NamedArray(Array([1 2; 3 4]), (["a","b"], [10,11]), (:rows,:cols))
convert(Array, x))

As far as I can tell, this only happens if some of the labels are integers that do not match up with the natural index numbers of their dimension. (If [10,11] were replaced with [1,2] in the NamedArray above, then convert works).

I looked in convert.jl to see how it's implemented, but following works fine:

x = NamedArray(Array([1 2; 3 4]), (["a","b"], [10,11]), (:rows,:cols))
x.array

So I'm not sure why convert(Array, x) throws an error.

Printing empty array doesn't work

Title says it all:

julia> NamedArray([])
0-element NamedArray{Any,1}:
Error showing value of type NamedArrays.NamedArray{Any,1,Array{Any,1},Tuple{Dict{ASCIIString,Int64}}}:
ERROR: ArgumentError: reducing over an empty collection is not allowed
 in _mapreduce(::Base.IdFun, ::Base.MaxFun, ::Base.LinearFast, ::Array{Union{},1}) at ./reduce.jl:139
 in maximum(::Array{Union{},1}) at ./reduce.jl:324
 in show(::Base.Terminals.TTYTerminal, ::NamedArrays.NamedArray{Any,1,Array{Any,1},Tuple{Dict{ASCIIString,Int64}}}, ::Int64) at /home/milan/.julia/NamedArrays/src/show.jl:123
 [inlined code] from ./tuple.jl:161
 in writemime(::Base.Terminals.TTYTerminal, ::MIME{symbol("text/plain")}, ::NamedArrays.NamedArray{Any,1,Array{Any,1},Tuple{Dict{ASCIIString,Int64}}}) at /home/milan/.julia/NamedArrays/src/show.jl:40
 [inlined code] from ./expr.jl:8
 in display(::Base.REPL.REPLDisplay{Base.REPL.LineEditREPL}, ::MIME{symbol("text/plain")}, ::NamedArrays.NamedArray{Any,1,Array{Any,1},Tuple{Dict{ASCIIString,Int64}}}) at ./REPL.jl:114
 [inlined code] from ./expr.jl:8
 in display(::Base.REPL.REPLDisplay{Base.REPL.LineEditREPL}, ::NamedArrays.NamedArray{Any,1,Array{Any,1},Tuple{Dict{ASCIIString,Int64}}}) at ./REPL.jl:117
 [inlined code] from ./multimedia.jl:151
 in display(::NamedArrays.NamedArray{Any,1,Array{Any,1},Tuple{Dict{ASCIIString,Int64}}}) at ./multimedia.jl:163
 in print_response(::Base.Terminals.TTYTerminal, ::Any, ::Void, ::Bool, ::Bool, ::Void) at ./REPL.jl:134
 in print_response(::Base.REPL.LineEditREPL, ::Any, ::Void, ::Bool, ::Bool) at ./REPL.jl:121
 in (::Base.REPL.##18#19{Bool,Base.REPL.##29#38{Base.REPL.LineEditREPL},Base.REPL.LineEditREPL,Base.LineEdit.Prompt})(::Base.LineEdit.MIState, ::Base.AbstractIOBuffer{Array{UInt8,1}}, ::Bool) at ./REPL.jl:630
 in run_interface(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface) at ./LineEdit.jl:1570
 in run_frontend(::Base.REPL.LineEditREPL, ::Base.REPL.REPLBackendRef) at ./REPL.jl:881
 in run_repl(::Base.REPL.LineEditREPL, ::Any) at ./REPL.jl:166
 in _start() at ./client.jl:361

name an 1-dim array

Hello! Thank you for this useful package!
I try to name the 1-dim array in the constructor like the following:
NamedArray([1,3,2,4],(["a","b","c","d"]))
However, an error Dimension mismatch appears.
Is there any method that can name a 1-dim array in the constructor? Doesn't quite understand the example indexing in the documentation.

Thanks! 😄

Pretty print arrays with more than 2 dimensions

This is related to: nalimilan/FreqTables.jl#7

julia> n = NamedArray(rand(Int16,2,4,2))
2x4x2 NamedArray{Int16,3}:
 A: ASCIIString["1" "2"] B: ASCIIString["1" "2" "3" "4"] C: ASCIIString["1" "2"]Int16[31781 -11386 1491 -24828
      -27467 31549 25144 7646]

Int16[26844 3264 -16108 -20493
      -17948 -28609 9881 -32396]

julia> rand(Int16,2,4,2)
2x4x2 Array{Int16,3}:
[:, :, 1] =
  1867  -19420   2793   24387
 18363  -21502  21898  -26883

[:, :, 2] =
 -1755  -14188   -2955  -11092
 25451  -14871  -29275  -14864

It could be like the base's Array display, with a header for each (pretty printed) 2D slide.

Incompatible with Julia 1.0?

julia> using NamedArrays
[ Info: Precompiling NamedArrays [86f7a689-2022-50b4-a561-43c23ac3c673]
ERROR: LoadError: LoadError: syntax: invalid "::" syntax
Stacktrace:
 [1] include at ./boot.jl:317 [inlined]
 [2] include_relative(::Module, ::String) at ./loading.jl:1038
 [3] include at ./sysimg.jl:29 [inlined]
 [4] include(::String) at /home/dabrowsa/.julia/packages/NamedArrays/gVcMl/src/NamedArrays.jl:11
 [5] top-level scope at none:0
 [6] include at ./boot.jl:317 [inlined]
 [7] include_relative(::Module, ::String) at ./loading.jl:1038
 [8] include(::Module, ::String) at ./sysimg.jl:29
 [9] top-level scope at none:2
 [10] eval at ./boot.jl:319 [inlined]
 [11] eval(::Expr) at ./client.jl:389
 [12] top-level scope at ./none:3
in expression starting at /home/dabrowsa/.julia/packages/NamedArrays/gVcMl/src/namedarraytypes.jl:14
in expression starting at /home/dabrowsa/.julia/packages/NamedArrays/gVcMl/src/NamedArrays.jl:18
ERROR: Failed to precompile NamedArrays [86f7a689-2022-50b4-a561-43c23ac3c673] to /home/dabrowsa/.julia/compiled/v1.0/NamedArrays/wPYCq.ji.
Stacktrace:
 [1] error(::String) at ./error.jl:33
 [2] macro expansion at ./logging.jl:313 [inlined]
 [3] compilecache(::Base.PkgId, ::String) at ./loading.jl:1184
 [4] macro expansion at ./logging.jl:311 [inlined]
 [5] _require(::Base.PkgId) at ./loading.jl:941
 [6] require(::Base.PkgId) at ./loading.jl:852
 [7] macro expansion at ./logging.jl:311 [inlined]
 [8] require(::Module, ::Symbol) at ./loading.jl:834

Warning on ambiguous method definitions

julia> using NamedArrays
WARNING: New definition 
    call(Type{NamedArrays.NamedArray}, AbstractArray{#T<:Any, #N<:Any}, NTuple{#N<:Any, Array{T<:Any, 1}}, NTuple{#N<:Any, T<:Any}) at /home/dzea/.julia/v0.4/NamedArrays/src/constructors.jl:25
is ambiguous with: 
    call(Type{NamedArrays.NamedArray}, AbstractArray{#T<:Any, #N<:Any}, NTuple{#N<:Any, Base.Associative}, NTuple{#N<:Any, T<:Any}) at /home/dzea/.julia/v0.4/NamedArrays/src/constructors.jl:14.
To fix, define 
    call(Type{NamedArrays.NamedArray}, AbstractArray{#T<:Any, #N<:Any}, Tuple{}, NTuple{#N<:Any, T<:Any})
before the new definition.
WARNING: New definition 
    call(Type{NamedArrays.NamedArray}, AbstractArray{#T<:Any, #N<:Any}, NTuple{#N<:Any, Array{T<:Any, 1}}) at /home/dzea/.julia/v0.4/NamedArrays/src/constructors.jl:31
is ambiguous with: 
    call(Type{NamedArrays.NamedArray}, AbstractArray{#T<:Any, #N<:Any}, NTuple{#N<:Any, Base.Associative}) at /home/dzea/.julia/v0.4/NamedArrays/src/constructors.jl:19.
To fix, define 
    call(Type{NamedArrays.NamedArray}, AbstractArray{#T<:Any, #N<:Any}, Tuple{})
before the new definition.
WARNING: New definition 
    +(AbstractArray{#T1<:Number, #N<:Any}, NamedArrays.NamedArray{#T2<:Number, #N<:Any, AT<:Any, DT<:Any}) at /home/dzea/.julia/v0.4/NamedArrays/src/arithmetic.jl:29
is ambiguous with: 
    +(Base.Range{#S<:Any}, AbstractArray{#T<:Any, N<:Any}) at arraymath.jl:87.
To fix, define 
    +(Base.Range{_<:Number}, NamedArrays.NamedArray{#T2<:Number, 1, AT<:Any, DT<:Any})
before the new definition.
WARNING: New definition 
    -(AbstractArray{#T1<:Number, #N<:Any}, NamedArrays.NamedArray{#T2<:Number, #N<:Any, AT<:Any, DT<:Any}) at /home/dzea/.julia/v0.4/NamedArrays/src/arithmetic.jl:29
is ambiguous with: 
    -(Base.Range{#S<:Any}, AbstractArray{#T<:Any, N<:Any}) at arraymath.jl:87.
To fix, define 
    -(Base.Range{_<:Number}, NamedArrays.NamedArray{#T2<:Number, 1, AT<:Any, DT<:Any})
before the new definition.
WARNING: New definition 
    -(NamedArrays.NamedArray, AbstractArray) at /home/dzea/.julia/v0.4/NamedArrays/src/arithmetic.jl:53
is ambiguous with: 
    -(AbstractArray{#S<:Any, N<:Any}, Base.Range{#T<:Any}) at arraymath.jl:78.
To fix, define 
    -(NamedArrays.NamedArray{#S<:Any, N<:Any, AT<:Any, DT<:Any}, Base.Range{T<:Any})
before the new definition.

Poor interaction with NullableArrays

NamedArrays don't work well with NullableArray currently. First, the type information isn't correct:

julia> NamedArray(NullableArray([1]))
1-element NamedArray{Nullable{Int64},1}:
...

I suggest printing NamedArray{NullableArray{Int64,1}}: or NullableArray{Int64,1} with names:. This pattern could be used for all array types.

Second, the printing is quite verbose, as Nullable{T} is repeated for each element. I think this should be fixed in Julia Base: JuliaLang/julia#15928.

getindex should return a NamedArray (even when using n[:])

Hello,

I noticed that

In[3]: n = NamedArray(rand(2,4,3))
Out[3]:
2×4×3 Named Array{Float64,3}

[:, :, C=1] =
A ╲ B │         1          2          3          4
──────┼───────────────────────────────────────────
10.746684   0.352576   0.859066  0.0463972
20.500173    0.32667   0.146571   0.796928

[:, :, C=2] =
A ╲ B │        1         2         3         4
──────┼───────────────────────────────────────
10.306856  0.242292  0.630703  0.548638
20.499724  0.184323  0.407832  0.684586

[:, :, C=3] =
A ╲ B │         1          2          3          4
──────┼───────────────────────────────────────────
10.841066  0.0542213   0.715639  0.0993138
20.312623   0.492007     0.5172   0.410809

In[4]: n[2,:,:]
Out[4]:
4×3 Named Array{Float64,2}
B ╲ C │        1         2         3
──────┼─────────────────────────────
10.500173  0.499724  0.312623
20.32667  0.184323  0.492007
30.146571  0.407832    0.5172
40.796928  0.684586  0.410809

but

In[5]: n[:]
Out[5]:
24-element Array{Float64,1}:
 0.746684 
 0.500173 
 0.352576 
 0.32667  
 0.859066 
 0.146571 
 0.0463972
 0.796928 
 0.306856 
 0.499724 
 0.242292 
 0.184323 
 0.630703 
 0.407832 
 0.548638 
 0.684586 
 0.841066 
 0.312623 
 0.0542213
 0.492007 
 0.715639 
 0.5172   
 0.0993138
 0.410809 

I was expecting a NamedArray to be returned

Kind regards

Subset of NamedArray with duplicates

Testing the new functionality.

Currently the following fails (it is unrelated to the changes):

julia> x = NamedArray([1 3; 2 4], ( ["a", "b"], ["c", "d"] ), ("Rows", "Cols"))
2×2 Named Array{Int64,2}
Rows ╲ Cols │ c  d
────────────┼─────
a           │ 1  3
b           │ 2  4

julia> x[["a","a"],:]
ERROR: Inconsistent dictionary sizes

and it is understandable why. @davidavdav But would you consider adding a more informative error message (just an idea - this is not crucial).

Check get(io, :limit, true) in show

Currently, the show method unconditionally checks displaysize in order to decide how much of the array to show.

It should probably check limit = get(io, :limit, true) ... if limit == false, then it should show the whole array. (:limit is the documented IOContext property used to decide whether to show all of an array).

views on NamedArrays are slow

Applying view on a NamedArray tends to be slow, probably because the dimnames Dicts are recalculated. I had a bit of trouble generating an MWE, but on a big (10.000 x 18.000) sparse Boolean NamedMatrix a I had @benchmark view($a, :, :) benchmark at 7 ms, while @benchmark view($(a.array), :, :) benchmarked at 20 ns, i.e. a speedup of a factor 300.000!

Matrix multiplication

I expected matrix multiplication to try to align matrices together before performing multiplication, but it doesn't. I wouldn't mind writing that code, if it's decided that it's the correct behavior.

x = NamedArray(Int[1 3; 2 4], ( ["A","B"], ["C","D"] ))
y = NamedArray(Int[1 3; 2 4], ( ["A","B"], ["D","C"] ))  # flipped D and C

> x * x   # I expected an error
A \ B C  D 
A     7  15
B     10 22

> x * x'  # this is correct
A \ A A  B 
A     10 14
B     14 20

> x * y'   # this isn't
A \ A A  B 
A     10 14
B     14 20 

Do not store names in two different objects

Currently names are duplicated in the names and dicts members. This is suboptimal in the long-term. It is probably possible to only use the dictionaries and to rebuild the ordered vector of names from it when needed. Since that vector is not typically needed in performance-critical operations, that's not a problem (indexing is fast thanks to dictionaries, and that's what matters). What do you think?

There is not array getter

Now that array() was deprecated there is not an array getter. Could be great to have a getter (getarray or similar) in order to not access directly the array field.

Best regards,

how to define a NamedVector?

I am trying to reduce a dimension from a matrix, but I cannot figure out the syntaxt to do it.
Example

# With normal arrays I would:
ar = rand(5,3)
ret = vec(sum(ar, 1))

# with named arrays I try:
nar = NamedArray(ar)
ret = NamedVector(sum(ar, 1)) # but this fails

I have tried all the combinations of parameters I could think of, including:

ret = sum(ar, 1)
ret = NamedVector(ret.array, (ret.dicts[2]), (ret.dimnames[2]))

Thanks!

Handling Any type

NamedArrays with Any type don't appear to be handled correctly. Here is a MWE:

using NamedArrays
raw = Array{Any}([1 2; 3 4])
data = NamedArray( raw )
println(2*raw)   # works fine
println(2*data)  # returns error

Here is the error message that is returned:

LoadError: MethodError: `indices` has no method matching indices(::Dict{ASCIIString,Int64}, ::CartesianIndex{2})
Closest candidates are:
  indices{K,V<:Integer}(::Associative{K,V<:Integer}, !Matched::Real)
  indices{T<:Integer,K,V<:Integer}(::Associative{K,V<:Integer}, !Matched::AbstractArray{T<:Integer,N})
  indices{K,V<:Integer}(::Associative{K,V<:Integer}, !Matched::AbstractArray{K,N})
  ...
while loading In[52], in expression starting on line 5

 in setindex! at C:\Users\Laurent\.julia\v0.4\NamedArrays\src\index.jl:104
 in .* at arraymath.jl:120
 in * at abstractarraymath.jl:54

Keeping names in *cat

Currently *cat of NamedArrays drop the column/row names. It would be nice if the behavior was the same as R, where names are merged in the dimension perpendicular to the bound and are kept in the other iff they overlap, dropped otherwise.

This would raise the question of what doing if two combined NamedArrays contain the same name for a row/column: warning and dropping names or error? R ignores this problem and permit that named vectors / matrices have multiple rows/cols with the same name (when you select that name it will return only the first istance among the cases).

I have already implemented an alternative hcat function that would keep names, but it's important to define the behavior in caso of conflicting names.

Functionality outside Base should be removed / deferred

With Julia 1.0, some library stuff has moved out of julia Base.

NamedArrays should probably lazy-load support for this stuff only when it is used, for instance with Requires.

First we need to find which things have moved out of Base, and needs to be loaded with using before it can be used.

size(n,1) NamedArray subset from a 2d NamedArray has broken name indexing

I'm very happy to have found this package. Having names on things prevents so many awful ordering bugs. Indexing by name is one of the best features of R. Thanks for bringing this to Julia!

It seems that when you subset a single column from a NamedArray matrix you get a NamedArray with broken name indexing. Also, why do the Dicts change type from Dict{ASCIIString,Int64} to Dict{Any,Int64} ? This doesn't seem to affect function, but I'm guessing that was unintended.

x = NamedArray([1 2 3; 4 5 6; 7 8 9], (["A","B","C"],["bob","joe","fred"]),("X","Y"))
x["A",:] # works
y = x[:,1:2]
y["A",:] # works
z = x[:,1]
z["A",:] # broken
foo = NamedArray([1,2,3],(["A","B","C"],),("FOO",))
foo["A"] # works

Precompilation failed in Julia v0.6-rc1

Here's the error message:

julia> using NamedArrays
INFO: Recompiling stale cache file C:\Users\ms5vs\.julia\lib\v0.6\Combinatorics.
ji for module Combinatorics.
WARNING: The call to compilecache failed to create a usable precompiled cache fi
le for module Combinatorics. Got:
WARNING: Module Iterators uuid did not match cache file.
ERROR: LoadError: Declaring __precompile__(true) is only allowed in module files
 being imported.
Stacktrace:
 [1] __precompile__(::Bool) at .\loading.jl:323
 [2] include_from_node1(::String) at .\loading.jl:552
 [3] eval(::Module, ::Any) at .\boot.jl:235
 [4] _require(::Symbol) at .\loading.jl:466
 [5] require(::Symbol) at .\loading.jl:386
 [6] _include_from_serialized(::String) at .\loading.jl:157
 [7] _require_from_serialized(::Int64, ::Symbol, ::String, ::Bool) at .\loading.
jl:194
 [8] _require_search_from_serialized(::Int64, ::Symbol, ::String, ::Bool) at .\l
oading.jl:224
 [9] _require(::Symbol) at .\loading.jl:422
 [10] require(::Symbol) at .\loading.jl:386
while loading C:\Users\ms5vs
\.julia\v0.6\Combinatorics\src\Combinatorics.jl, in
expression starting on line 1

broadcast with only one named matrix doesn't work

Hi!

broadcast with only one named matrix doesn't work because the assertion nargs > 1 in verify_names.

julia> mat = rand(1:20,4,4)
4×4 Array{Int64,2}:
  7  2  11   9
  1  1  12  19
 18  6  10  18
  7  2  19  13

julia> namedmat = NamedArray(mat)
4×4 Named Array{Int64,2}
A ╲ B │  1   2   3   4
──────┼───────────────
17   2  11   9
21   1  12  19
318   6  10  18
47   2  19  13

julia> string.(mat)
4×4 Array{String,2}:
 "7"   "2"  "11"  "9" 
 "1"   "1"  "12"  "19"
 "18"  "6"  "10"  "18"
 "7"   "2"  "19"  "13"

julia> string.(namedmat)
ERROR: AssertionError: nargs > 1
 in verify_names(::NamedArrays.NamedArray{Int64,2,Array{Int64,2},Tuple{DataStructures.OrderedDict{String,Int64},DataStructures.OrderedDict{String,Int64}}}, ::Vararg{NamedArrays.NamedArray{Int64,2,Array{Int64,2},Tuple{DataStructures.OrderedDict{String,Int64},DataStructures.OrderedDict{String,Int64}}},N}) at /home/dzea/.julia/v0.5/NamedArrays/src/keepnames.jl:28
 in broadcast(::Function, ::NamedArrays.NamedArray{Int64,2,Array{Int64,2},Tuple{DataStructures.OrderedDict{String,Int64},DataStructures.OrderedDict{String,Int64}}}) at /home/dzea/.julia/v0.5/NamedArrays/src/keepnames.jl:47

Best

Type stability of NamedArrays

When working on nalimilan/FreqTables.jl#19 we hit a problem of type inference of NamedArrays. Would it be possible to fix it?

Inference fails even the simplest constructor:

julia> @code_warntype NamedArray([1,2,3])
Variables:
  #self#::Type{NamedArrays.NamedArray}
  array::Array{Int64,1}

Body:
  begin
      SSAValue(0) = (Core.tuple)((Base.arraysize)(array::Array{Int64,1}, 1)::Int64)::Tuple{Int64}
      return $(Expr(:invoke, MethodInstance for NamedArrays.NamedArray(::Array{Int64,1}, ::Array{Array{String,1},1}, ::Array{Symbol,1}), :(#self#), :(array), :($(Expr(:invoke, MethodInstance for collect(::Base.Generator{Tuple{Int64},NamedArrays.#defaultnames}), :(Base.collect), :($(Expr(:new, Base.Generator{Tuple{Int64},NamedArrays.#defaultnames}, :($(QuoteNode(NamedArrays.defaultnames))), SSAValue(0))))))), :($(Expr(:invoke, MethodInstance for collect(::Base.Generator{UnitRange{Int64},NamedArrays.#defaultdimname}), :(Base.collect), :($(Expr(:new, Base.Generator{UnitRange{Int64},NamedArrays.#defaultdimname}, :($(QuoteNode(NamedArrays.defaultdimname))), :($(Expr(:new, UnitRange{Int64}, 1, :((Base.select_value)((Base.sle_int)(1, 1)::Bool, 1, (Base.sub_int)(1, 1)::Int64)::Int64))))))))))))
  end::Any

similar problems propagate to other operations (broadcasting, summing over margins, ...).

Key returned instead of val when key is Integer

Got a BoundsError when one of the dims was an Integer, this seems to be because instead of returning the index, indices(d,i) returned the key. It looks like it's hitting line 68 of index.jl instead of a different indices method. I was able to workaround this by converting the integer dimension to string (as it is functionally categorical data), but the behavior was unexpected.

Minor pretty printing glitch in Jupyter notebook

See below for example ouput that I'm seeing.

I'm not seeing this in the REPL, just Jupyter notebook (perhaps this is rather a Jupyter bug?). I'm on NamedArrays master, Julia 0.5rc3, and jupyter-notebook 4.2.1. I'm happy to provide any other info that might be needed to reproduce this!

26×15 Named Array{Float64,2}
A ╲ B │   1    2    3    4    5    6    7  …    9   10   11   12   13   14   15
──────┼────────────────────────────────────────────────────────────────────────
1     │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0  …  1.0  1.0  1.0  1.0  1.0  1.0  1.0
2     │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
3     │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
4     │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
5     │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
6     │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
7     │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
8     │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
9     │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
10    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
11    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
12    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
⋮         ⋮    ⋮    ⋮    ⋮    ⋮    ⋮    ⋮  ⋱    ⋮    ⋮    ⋮    ⋮    ⋮    ⋮    ⋮
15    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
16    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
17    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
18    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
19    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
20    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
21    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
22    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
23    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
24    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
25    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0     1.0  1.0  1.0  1.0  1.0  1.0  1.0
26    │ 1.0  1.0  1.0  1.0  1.0  1.0  1.0  …  1.0  1.0  1.0  1.0  1.0  1.0  1.0

Error when a NamedArray is indexed with a BitMatrix

Hi!
I found this error trying to index a bidimensional named array with a bidimensional bit array.

julia> mat = NamedArray(rand(1:10,2,3))
2×3 Named Array{Int64,2}
A ╲ B │  1   2   3
──────┼───────────
1     │  3   3   9
2     │ 10   1   4

julia> mask = mat .== 3
2×3 BitArray{2}:
  true   true  false
 false  false  false

julia> mat[mask]
ERROR: MethodError: no method matching NamedArrays.NamedArray{T,N,AT,DT}(::Array{Int64,1}, ::Tuple{Array{String,1},Array{String,1}}, ::Tuple{Symbol,Symbol})
Closest candidates are:
  NamedArrays.NamedArray{T,N,AT,DT}{T,N}(::AbstractArray{T,N}, ::Tuple{}, ::Tuple{Vararg{T,N}}) at /home/diego/.julia/v0.5/NamedArrays/src/constructors.jl:18
  NamedArrays.NamedArray{T,N,AT,DT}{T,N}(::AbstractArray{T,N}, ::Tuple{}) at /home/diego/.julia/v0.5/NamedArrays/src/constructors.jl:19
  NamedArrays.NamedArray{T,N,AT,DT}{T,N}(::AbstractArray{T,N}, ::Tuple{Vararg{DataStructures.OrderedDict,N}}) at /home/diego/.julia/v0.5/NamedArrays/src/constructors.jl:30
  ...
 in namedgetindex(::NamedArrays.NamedArray{Int64,2,Array{Int64,2},Tuple{DataStructures.OrderedDict{String,Int64},DataStructures.OrderedDict{String,Int64}}}, ::BitArray{2}) at /home/diego/.julia/v0.5/NamedArrays/src/index.jl:116
 in getindex(::NamedArrays.NamedArray{Int64,2,Array{Int64,2},Tuple{DataStructures.OrderedDict{String,Int64},DataStructures.OrderedDict{String,Int64}}}, ::BitArray{2}) at /home/diego/.julia/v0.5/NamedArrays/src/index.jl:11

julia> array(mat)[mask]
2-element Array{Int64,1}:
 3
 3

Best!

Support Datetime index

Datetime is getting merged into Base and it would be nice to have this type (Date{ISOCalendar} available as a valid row index.

I tried this on the off-chance it would just work.

julia> using Datetime #for now at least

julia> n = NamedArray(rand(2,4));

julia> dates = [today(), today()+days(1)]
2-element Array{Date{ISOCalendar},1}:
 2014-01-27
 2014-01-28

julia> setnames!(n, dates, 1)
[2014-01-27=>1,2014-01-28=>2]

julia> n
2x4 NamedArray{Float64,2}
Evaluation succeeded, but an error occurred while showing value of type NamedArray{Float64,2}:
ERROR: no method display(NamedArray{Float64,2})
 in display at multimedia.jl:158

I tried messing around with defining show methods but would need to get more involved with NamedArrays code to provide a viable PR.

This was mentioned as a alternative solution in this thread about the direction of TimeSeries: JuliaStats/Roadmap.jl#6

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.