My take:

How I did it
Since tikz is not well suited for this kind of graphic (which has to find intersections between planes, decomposing the figure in sub-objects and draw them in the correct order so that the nearest one hide the farthest ones) I used sketch, which can do these things and produce tikz code as result.
Next is the skecth code. The grid is a 5x5x5 cube. The water level is a real between 0 and 5. As for the height of each prism, unfortunately sketch does not provide primitives for reading numbers from files, nor to do list or array manipulation, so I had to draw each bar "one by one", instead of using a loop, and "hardcoded" their height in each case (the second number in the scale operation) :-(
def water_level 2.3
def prism {
sweep[fill style=prism]
{ 4<>, rotate(360/4,[0,1,0]) }
line[fill style=prism](0.5,0,0.5)(0.5,1,0.5)
}
def water {
sweep[fill style=water]
{ 4<>, rotate(360/4,[0,1,0]) }
line[fill style=water, style=water](2.52,0,2.52)(2.52, 1, 2.52)
}
def grid {
put { translate([0, 0, 0]) then scale([1, 5, 1])}{ {prism} }
put { translate([1, 0, 0]) then scale([1, 4.5, 1])}{ {prism} }
put { translate([2, 0, 0]) then scale([1, 4.3, 1])}{ {prism} }
put { translate([3, 0, 0]) then scale([1, 4.8, 1])}{ {prism} }
put { translate([4, 0, 0]) then scale([1, 5, 1])}{ {prism} }
put { translate([0, 0, 1]) then scale([1, 4.5, 1])}{ {prism} }
put { translate([1, 0, 1]) then scale([1, 2, 1])}{ {prism} }
put { translate([2, 0, 1]) then scale([1, 2.2, 1])}{ {prism} }
put { translate([3, 0, 1]) then scale([1, 4, 1])}{ {prism} }
put { translate([4, 0, 1]) then scale([1, 4.9, 1])}{ {prism} }
put { translate([0, 0, 2]) then scale([1, 4.5, 1])}{ {prism} }
put { translate([1, 0, 2]) then scale([1, 2, 1])}{ {prism} }
put { translate([2, 0, 2]) then scale([1, 2.2, 1])}{ {prism} }
put { translate([3, 0, 2]) then scale([1, 4, 1])}{ {prism} }
put { translate([4, 0, 2]) then scale([1, 4.5, 1])}{ {prism} }
put { translate([0, 0, 3]) then scale([1, 4.0, 1])}{ {prism} }
put { translate([1, 0, 3]) then scale([1, 3.0, 1])}{ {prism} }
put { translate([2, 0, 3]) then scale([1, 3.2, 1])}{ {prism} }
put { translate([3, 0, 3]) then scale([1, 3.5, 1])}{ {prism} }
put { translate([4, 0, 3]) then scale([1, 3.0, 1])}{ {prism} }
put { translate([0, 0, 4]) then scale([1, 3.5, 1])}{ {prism} }
put { translate([1, 0, 4]) then scale([1, 2.8, 1])}{ {prism} }
put { translate([2, 0, 4]) then scale([1, 3.0, 1])}{ {prism} }
put { translate([3, 0, 4]) then scale([1, 3.5, 1])}{ {prism} }
put { translate([4, 0, 4]) then scale([1, 2.5, 1])}{ {prism} }
put { translate([2, 0, 2]) then scale([1, water_level, 1])}{ {water} }
}
put{ view((10,20,20)) }{{grid}} % Draw it!
global { language tikz }
You save this code in a file named elevation-grid.sketch and compile it with:
$ sketch elevation-grid.sketch > tikzpicture.tex
Then, your main elevation-grid.tex document looks like this:
\documentclass{standalone}
\usepackage{tikz}
\tikzset{
prism/.style = {draw=black, fill=black!30, opacity=1},
water/.style = {draw=black, fill=blue, opacity=0.60},
}
\begin{document}
\input{tikzpicture.tex}
\end{document}
Of course this generates the graphic for a paticular water level (2.8 in the example). To generate the animation, you have to repeat the above a lot of times, for different water_level values. In order to automate this process, I removed the water_level definition from the first line of elevation-grid.sketch and wrote this small shell script (it requires convert utility from Imagemagick):
echo "def water_level $1" > aux.sketch
cat elevation-grid.sketch >> aux.sketch
sketch aux.sketch > tikzpicture.tex
pdflatex elevation-grid.tex
convert -density 300 elevation-grid.pdf elevation-grid-$1.png
If you save this code in a file named run, for example, you may call it with:
$ sh run 1.2
$ sh run 1.3
$ sh run 1.4
etc...
and you'll get a set of png files: elevation-grid-1.2.png, elevation-grid-1.3.png, and so on. Of course I also automated the above to generate values between 1.0 and 3.9. When all png figures were finally generated, I converted them to an animated gif with convert again:
$ convert -delay 20 elevation-grid*png animation.gif
Update

Now the sketch script is generated by a python script. Currently the data for the grid
is randomly generated, but it would be trivial to read it from a file. This is the script:
import random
def randomGrid(x,y,z):
grid = []
for i in range(y):
row = []
for j in range(x):
row.append(random.random()*z+1)
grid.append(row)
return grid
def generateGraphic(grid, water_level):
code = []
code.append("def grid {")
y = 0
for row in grid:
x = 0
for cell in row:
code.append(" put { translate([%d, 0, %d]) then scale([1, %f, 1])}{ {prism} }" % (x, y, cell))
x = x + 1
code.append("")
y = y + 1
code.append("put { scale([%f, %f, %f]) then translate([%f, 0, %f])}{ {water} }" % (x+0.01, water_level, y+0.01, x/2.0-0.5, y/2.0-0.5))
code.append("}")
return "\n".join(code)
def preamble():
return """
def prism {
sweep[fill style=prism]
{ 4<>, rotate(360/4,[0,1,0]) }
line[fill style=prism](0.5,0,0.5)(0.5,1,0.5)
}
def water {
sweep[fill style=water]
{ 4<>, rotate(360/4,[0,1,0]) }
line[fill style=water, style=water](0.5,0,0.5)(0.5, 1, 0.5)
}
"""
def final(camera):
return """put{ view((%f,%f,%f)) }{{grid}} %% Draw it!
global { language tikz }""" % camera
g = randomGrid(20,20,7) % 20x20 cells, max height =7
print preamble()
print generateGraphic(g, 4.2) % 4.2 is the water level
print final(camera=(30,60,60)) % 3D position of camera, looking at origin
To be used like this:
$ python generate-sketch.py > elevation-grid.sketch