I have a challenging transform I'm trying to accomplish as I try to improve the performance of my 3D GAN.


I've been working with data from Berkeley's PEER Ground Motion Database to generate new novel seismic traces. (Real traces shown above.) Coming from a background in engineering my initial attempt involved decomposing the traces into their {X,Y,Z} components, however, the results were less than satisfying, and were subject to repeated mode collapse. There might be ways to fix this with more time and resources but I thought I would try another approach first.


I still have a bit of time to work with data, and was looking to solicit methods of turning this {X,Y,Z} point data into something more digestible by a 3D convolutional network. Each of the 788 traces is scaled {-1,1) across all axis and interpolated to 4000 steps. An example of one of the training samples can be seen here in a git Gist link. My knowledge of the subject matter suggests I need to transform this data into some type of array with places a True if there is a trace point there and False if void. My idea is that once that region keys and boolean values are computed I will render them.


I couldn't find away to do this strictly numerically like I have previous with 2D histograms with thousands of bins and tens of thousands of points. Nothing jumped out at me immediately on the Volume Rendering guide but there might be users with more experience in that area. Right now my code is working but slow on the account of having to process through divisions^3 regions. AnyTrue stops processing through the points as soon as it finds one regional member, but the cubic rise in computation is a problem, especially if I'd like to keep the resolution high like the original data. Even 10x10x10 divisions is taking way too long to be practical, and is not an amenable approach to processing 788 examples.

dividedVolumes[steps_Integer] := 
 Module[{var, sidelength, div, shape},
  sidelength = 2/(steps - 1);
  div = ((Abs[-1 + sidelength/2]) + (1 - sidelength/2))/(steps - 1);
  var = Tuples[
    Range[-1 + div/2, 1 - div/2, div], 3
  If[Power[steps, 3] != Length@var, 
   Print[Style["Make Ordered Grid Warning", Red, 20]], Nothing];
  shape = Cube[#, div] & /@ var;
  Region /@ shape

checkRegion[reg_, pts_] := Return[
  <|reg -> AnyTrue[pts, RegionMember[reg, # ] & ]|>

processTrace[rawSet_] := Module[{vol, set, steps = 10},
  vol = dividedVolumes[steps];
  set = rawSet[[All, {"x", "y", "z"}]] // Values;
  checkRegion[#, set] & /@ vol

 processTrace[testset] // inputed linked code snippet

I'm a bit overwhelmed about where to take this code next if anyone has any suggestions about how to transform this type of trace data. Are there any similar problems I can adopt strategies from?

  • $\begingroup$ The seismic traces look like 3D curves. If you want to generate realistic examples then you should probably not represent them as 3D volumes as this loses the ordered curve-like nature of the trace. Instead do a bit of feature engineering. 1) resample the curves so they all have the same number of points - uniformly spaced along the curves 2) Take the derivatives (differences) in x,y,z to get three waveforms, 3) fourier transform these waveforms and keep n frequency components of each so you have feature vector {fx1,fx2,fx3, ..., fy1,fy2,fy3,..., fz1,fz2,fz3,...}. Feed these vectors to the GAN $\endgroup$
    – flinty
    Commented Oct 24, 2020 at 11:56
  • $\begingroup$ ^ reconstruction is just a matter of 1) get a result from the GAN, 2) chop the result (a three part fourier vector) into 3 pieces each of length n, 3) inverse fourier transform each, 4) accumulate the result and Rescale to {{-1,1},{-1,1},{-1,1}} space. $\endgroup$
    – flinty
    Commented Oct 24, 2020 at 11:59
  • $\begingroup$ Good suggestion.. Luckily I've done Fourier Analysis on these curves already as part of the project so that code is ready to go. I've also previously resampled curves to have evenly spaced points but nothing this complex. $\endgroup$
    – BBirdsell
    Commented Oct 24, 2020 at 15:33
  • $\begingroup$ @flinty You were so helpful you sent me down another path of exploration. I'm a bit stuck on how to generate the {x,y,z} waveforms in step 2 and how to apply the FT to them. The code I'm currently using returns it w.r.t time but I imagine you might have had a simpler pure MMA way to do it? If you have a moment to make another comment. thx, $\endgroup$
    – BBirdsell
    Commented Oct 26, 2020 at 22:41
  • $\begingroup$ {wx,wy,wz} = Transpose[Differences[Values[data][[All, 2 ;;]]]] then maybe {fx,fy,fz} = FourierDCT[#,1]&/@{wx,wy,wz}. You want the DCT because it's real valued, and type-I DCT so it's easily invertible with another type-I DCT. $\endgroup$
    – flinty
    Commented Oct 27, 2020 at 10:16

1 Answer 1


This bins the trace as a 3D image almost instantly:

(* take data of the form <|set->S,x->X,y->Y,z->Z|> and return a list of {X,Y,Z} *)
coordinates = Values[data][[All, 2 ;;]];
ranges = MinMax /@ Transpose[coordinates];
divisions = 80;
binspecs = Append[#, (#[[2]] - #[[1]])/divisions] & /@ ranges;
Image3D[Unitize@BinCounts[coordinates, Sequence @@ binspecs]]



Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.