diff --git a/README.md b/README.md index d3baade..80c00d4 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,13 @@ julia> propertynames(chain) (:id, :atoms, :sequence, :numbering, :ins_codes, :renumbering) ``` -To store additional properties, `addproperties` can be used to attach persistent chain-level properties or indexable residue-level properties: +To store additional properties, `addpropertie!s` can be used to attach persistent chain-level properties or indexable residue-level properties: ```julia -julia> new_chain = addproperties(chain; taxid=83332) +julia> addproperties!(chain; taxid=83332) 256-residue ProteinChain{Float64} (A) -julia> new_chain = addproperties(new_chain; rand3=IndexableProperty(rand(3,256))) # last dimension matches chain length +julia> addproperties!(new_chain; rand3=IndexableProperty(rand(3,256))) # last dimension matches chain length 256-residue ProteinChain{Float64} (A) julia> new_chain[1:100].rand3 diff --git a/src/ProteinChains.jl b/src/ProteinChains.jl index 000ff24..fe3e2f7 100644 --- a/src/ProteinChains.jl +++ b/src/ProteinChains.jl @@ -10,6 +10,7 @@ export Atom include("properties.jl") export AbstractProperty, StandardProperty, IndexableProperty +export setproperties!, addproperties!, removeproperties! export setproperties, addproperties, removeproperties include("chain.jl") diff --git a/src/chain.jl b/src/chain.jl index 3f13444..01e3d2a 100644 --- a/src/chain.jl +++ b/src/chain.jl @@ -2,7 +2,7 @@ ProteinChain{T<:Real} Represents a protein chain with a basic set of fields from which some other properties might be derived. -The [`addproperties`](@ref) function can be used to instantiate new chains with additional properties. +The [`addproperties!`](@ref) function can be used to add additional properties. ## Fields - `id::String`: Identifier for the protein chain. @@ -12,10 +12,10 @@ The [`addproperties`](@ref) function can be used to instantiate new chains with - `numbering::Vector{Int32}`: Residue numbering (author). See [`renumber`](@ref) for renumbering. - `properties::ProteinChains.NamedProperties`: Named properties associated with the chain. -See also [`addproperties`](@ref), [`StandardProperty`](@ref), [`IndexableProperty`](@ref). +See also [`addproperties!`](@ref), [`StandardProperty`](@ref), [`IndexableProperty`](@ref). ``` """ -struct ProteinChain{T<:Real} +mutable struct ProteinChain{T<:Real} id::String atoms::Vector{Vector{Atom{T}}} sequence::String @@ -45,7 +45,7 @@ function ProteinChain{T}(id, atoms, sequence, ins_codes, numbering::Vector{<:Int end function ProteinChain(id, atoms::Vector{Vector{Atom{T}}}, sequence, ins_codes=String(fill(0x40, length(sequence))), numbering=collect(1:length(sequence)), properties=(;)) where T - ProteinChain{T}(id, atoms, sequence, ins_codes, Int32.(numbering), namedproperties(properties)) + ProteinChain{T}(id, atoms, sequence, ins_codes, numbering, properties) end Base.convert(::Type{ProteinChain{T}}, chain::ProteinChain) where T = @@ -60,7 +60,7 @@ Base.length(chain::ProteinChain) = length(chain.atoms) function Base.getindex(chain::ProteinChain, i::Union{AbstractVector,Colon}) properties = map(p -> p[i], chain.properties) - ProteinChain(chain.id, chain.atoms[i], chain.sequence[i], chain.numbering[i], properties) + ProteinChain(chain.id, chain.atoms[i], chain.sequence[i], chain.ins_codes[i], chain.numbering[i], properties) end Base.getproperty(chain::ProteinChain, name::Symbol) = @@ -68,12 +68,14 @@ Base.getproperty(chain::ProteinChain, name::Symbol) = Base.propertynames(chain::ProteinChain, private::Bool=false) = (setdiff(fieldnames(ProteinChain), private ? () : (:properties,))..., propertynames(chain.properties)...) -setproperties(chain::ProteinChain, ps::NamedTuple) = - ProteinChain(chain.id, chain.atoms, chain.sequence, chain.ins_codes, chain.numbering, setproperties(chain.properties, ps)) +function setproperties!(chain::ProteinChain, ps::NamedTuple) + chain.properties = setproperties(chain.properties, ps) + chain +end """ - addproperties(chain::ProteinChain, properties::NamedTuple) - addproperties(chain::ProteinChain; properties...) + addproperties!(chain::ProteinChain, properties::NamedTuple) + addproperties!(chain::ProteinChain; properties...) Creates a new `ProteinChain` instance with the added properties. Indexing of property values can be specified with a wrapper type, @@ -81,17 +83,17 @@ such as `IndexableProperty`. See also [`removeproperties`](@ref), [`IndexableProperty`](@ref). """ -addproperties(chain::ProteinChain, properties::NamedTuple) = setproperties(chain, addproperties(chain.properties, properties)) -addproperties(chain::ProteinChain; properties...) = setproperties(chain, addproperties(chain.properties, NamedTuple(properties))) +addproperties!(chain::ProteinChain, properties::NamedTuple) = setproperties!(chain, addproperties(chain.properties, properties)) +addproperties!(chain::ProteinChain; properties...) = setproperties!(chain, addproperties(chain.properties, NamedTuple(properties))) """ - removeproperties(chain::ProteinChain, names::Symbol...) + removeproperties!(chain::ProteinChain, names::Symbol...) Creates a new `ProteinChain` instance with the property names in `names` removed. -See also [`addproperties`](@ref) +See also [`addproperties!`](@ref) """ -removeproperties(chain::ProteinChain, names::Symbol...) = setproperties(chain, removeproperties(chain.properties, names...)) +removeproperties!(chain::ProteinChain, names::Symbol...) = setproperties!(chain, removeproperties(chain.properties, names...)) Base.summary(chain::ProteinChain) = "$(length(chain))-residue $(typeof(chain)) ($(chain.id))" diff --git a/src/properties.jl b/src/properties.jl index 3b1bcb5..f56afaa 100644 --- a/src/properties.jl +++ b/src/properties.jl @@ -20,6 +20,14 @@ addproperties(properties::NamedProperties, newproperties::NamedTuple) = removeproperties(properties::NamedProperties, names::Symbol...) = NamedTuple{filter(name -> name ∉ names, propertynames(properties))}(properties) +function setproperties! end +function addproperties! end +function removeproperties! end + +setproperties(x, args...) = setproperties!(deepcopy(x), args...) +addproperties(x, args...; kwargs...) = addproperties!(deepcopy(x), args...; kwargs...) +removeproperties(x, args...) = removeproperties!(deepcopy(x), args...) + checkproperty(::Any, ::AbstractProperty) = nothing unpack(x) = x @@ -32,7 +40,7 @@ unpack(p::AbstractProperty) = p.value A property with arbitrary type. The value is retained as is. -This is the default property type for [`addproperties`](@ref). +This is the default property type for [`addproperties!`](@ref). See also [`IndexableProperty`](@ref). """ @@ -53,7 +61,7 @@ residue indexing of the chain being propagated to the last dimension of the arra ```jldoctest julia> chain = pdb"1ASS"A; -julia> chain = addproperties(pdb"1ASS"A; y=IndexableProperty(rand(2,152))); +julia> addproperties!(pdb"1ASS"A; y=IndexableProperty(rand(2,152))); julia> chain.y == chain[1:10].y false diff --git a/src/structure.jl b/src/structure.jl index 808da5b..c408583 100644 --- a/src/structure.jl +++ b/src/structure.jl @@ -7,7 +7,7 @@ - `chains::Vector{ProteinChain{T}}`: a collection of `ProteinChain`s. - `properties::NamedProperties`: arbitrary properties. """ -struct ProteinStructure{T} <: AbstractVector{ProteinChain{T}} +mutable struct ProteinStructure{T} <: AbstractVector{ProteinChain{T}} name::String atoms::Vector{Atom{T}} chains::Vector{ProteinChain{T}} @@ -30,7 +30,11 @@ chainid_to_index(structure::ProteinStructure, id::AbstractString) = findfirst(c Base.getindex(structure::ProteinStructure, i::Integer) = structure.chains[i] Base.getindex(structure::ProteinStructure, id::AbstractString) = structure[chainid_to_index(structure, id)] -Base.getindex(structure::ProteinStructure, is::AbstractVector) = ProteinStructure(structure.name, structure.atoms, map(i -> structure[i], is)) + +function Base.getindex(structure::ProteinStructure, inds::AbstractVector{<:Integer}) + properties = map(p -> p[inds], structure.properties) + return ProteinStructure(structure.name, structure.atoms, map(i -> structure[i], inds), properties) +end Base.setindex!(structure::ProteinStructure, chain::ProteinChain, i::Integer) = (structure.chains[i] = chain) Base.setindex!(structure::ProteinStructure, chain::ProteinChain, id::AbstractString) = (structure.chains[chainid_to_index(structure, id)] = chain) @@ -68,14 +72,16 @@ Base.getproperty(structure::ProteinStructure, name::Symbol) = Base.propertynames(structure::ProteinStructure, private::Bool=false) = (setdiff(fieldnames(ProteinStructure), private ? () : (:properties,))..., propertynames(structure.properties)...) -setproperties(structure::ProteinStructure, properties::NamedTuple) = - ProteinStructure(structure.name, structure.atoms, structure.chains, setproperties(structure.properties, properties)) +function setproperties!(structure::ProteinStructure, properties::NamedTuple) + structure.properties = setproperties(structure.properties, properties) + structure +end -addproperties(structure::ProteinStructure, properties::NamedTuple) = - setproperties(structure, addproperties(structure.properties, properties)) +addproperties!(structure::ProteinStructure, properties::NamedTuple) = + setproperties!(structure, addproperties(structure.properties, properties)) -addproperties(structure::ProteinStructure; properties...) = - setproperties(structure, addproperties(structure.properties, NamedTuple(properties))) +addproperties!(structure::ProteinStructure; properties...) = + setproperties!(structure, addproperties(structure.properties, NamedTuple(properties))) -removeproperties(structure::ProteinStructure, names::Symbol...) = - setproperties(structure, removeproperties(structure.properties, names...)) +removeproperties!(structure::ProteinStructure, names::Symbol...) = + setproperties!(structure, removeproperties(structure.properties, names...)) diff --git a/test/runtests.jl b/test/runtests.jl index 9cc860c..e92a734 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,12 +3,6 @@ using Test @testset "ProteinChains.jl" begin - @testset "ideal.jl" begin - geometry = BackboneGeometry(N_Ca_length=3, Ca_C_length=3, N_Ca_C_angle=π/2) - ideal_residue = IdealResidue{Float64}(geometry) - @test ideal_residue == Float64[-2 1 1; -1 -1 2; 0 0 0] - end - @testset "atom.jl" begin @testset "atom name" begin