Why modyfing view do not lead to modification of source array

Hello I have some 3 dimensional array (CT scan) - then for convinience I define view to given slice (slicing can be done in diffrent dimensions so that is why I have this meta.parse…). I want to be able to modify source 3 dimensional array by modifying the 2 dimensional view - what am I doing wrong?

below structs holding data

abstract type RawDataToDisp end

```@doc

2 dimensional ata for displaying single slice

struct is mutable becouse in case of the masks data can be changed multiple times and rapidly   

```

@with_kw mutable struct TwoDimRawDat{T} <: RawDataToDisp

   type::Type{T}= UInt8# easy access to type

   name::String=""#associated name

   dat::Array{T, 2}=ones(type,2,2)# raw pixel data

end#2DimRawDat

```@doc

3 dimensional data for displaying single slice

struct is mutable becouse in case of the masks data can be changed multiple times and rapidly   

```

@with_kw mutable struct ThreeDimRawDat{T} <: RawDataToDisp

   type::Type{T}= UInt8# easy access to type

   name::String=""#associated name

   dat::Array{T, 3}=ones(type,2,2,2)# raw voxel data

end#2DimRawDat

functions defined to work on this structs

```@doc

given two dim dat it sets points in given coordinates in given slice to given value

coords - coordinates in a plane of chosen slice to modify

value - value to set for given points

return reference to modified slice

```

function modSlice!(data::TwoDimRawDat{T}

                ,coords::Vector{CartesianIndex{2}}

                ,value::T ) where {T}

   data.dat[coords].=value

   data.dat

end#modSlice

```@doc

gives access to the slice of intrest - way of slicing is defined at the begining

typ - type of data 

slice - slice we want to access

sliceDim - on the basis of what dimension we are slicing

return 2 dimensional array  wrapper -TwoDimRawDat  object representing slice of given 3 dimensional array

!! important returned TwoDimRawDat holds view to the original 3 dimensional data  

```

function threeToTwoDimm(typ::Type{T}

                ,slice::Int

                ,sliceDim::Int

                ,threedimDat::ThreeDimRawDat{T})::TwoDimRawDat{T} where {T}

                arr=[":",":",":"]

                arr[sliceDim]="$slice"

               return TwoDimRawDat{T}(typ,threedimDat.name,view(threedimDat.dat,eval(Meta.parse(arr[1])),eval(Meta.parse(arr[2])),eval(Meta.parse(arr[3]))   )   )

end#ThreeToTwoDimm

Then I test It on zero arrays of appropriate types and dimensionality

        zz=..# this is some TwoDimRawDat
        sa= zz.dat # 3 dim array
        maximum(sa) # 0 - as should be 
        tD= threeToTwoDimm(zz.type,2,2,zz  ) # creating view in struct 
        modSlice!(tD, [CartesianIndex(1,1)], UInt8(3)) # modyfing view
        maximum(tD.dat)# is 3 as expected
maximum(sa)# still 0!!! - why?

thanks for help!

I took the liberty of editing your post to change block (text) quotes to use code quoting instead — please use that in the future to help make your posts more readable.

On the actual question, I really want to dissuade you from using Meta.parse and eval. Instead, you can use selectdim to just do this operation for you (if I’m understanding it correctly).

Ok, that’s still not addressing the actual question… the root of the challenge you asked about is that TwoDimRawDat has its dat field defined as an Array{T,3}. This doesn’t support views and will convert (and thus copy) any non-Array as needed/able. If you want your TwoDimRawDat struct to support holding views, you need to change that field to also allow SubArrays (likely by allowing all AbstractArrays in general).

6 Likes