Graph bar with elevation/height values
This script will generate a legend plane with text on the 2nd layer.



This script assumes the terrain object's name is "Plane".
To change it, change the object's name in line 7:

obj = bpy.data.objects['Plane'] # Reference terrain object

The color ramp was generated according to the example in the question above (3 swatches with pure green, blue and red in that order). Anyway, the script takes the colors from the original terrain object's color ramp.

It also generates 7 rungs to the legend's ladder according to the provided example. To change this, find the rungs variable i the script and change its value.

import bpy
from math import radians

def update_legend( scene ):
    C = bpy.context

    ## Get global height coordinates of terrain vertices
    obj = bpy.data.objects['Plane'] # Reference terrain object
    m = obj.to_mesh( C.scene, True, 'RENDER' )

    offset  = 0.5 # The value placed in the math.add node
    heights = [ v.co.z + offset for v in m.vertices ]

    minZ = min( heights )
    maxZ = max( heights )

    ## Generate legend color bar

    legendPlane = None
    if 'legend' in bpy.data.objects:
        legendPlane = bpy.data.objects[ 'legend' ]
    else:
        # Add legened plane on layer 2
        bpy.ops.mesh.primitive_plane_add( layers = [ i == 1 for i in range(20) ] )

        legendPlane = bpy.data.objects[ C.object.name ]
        legendPlane.name = 'legend'
        legendPlane.dimensions.y = 20

        bpy.ops.object.transform_apply( scale = True ) # Apply scale (dim change)

        # Setup legend material
        cr = obj.active_material.node_tree.nodes['ColorRamp']

        legendMat = None
        if "legend" not in bpy.data.materials:
            legendMat = bpy.data.materials.new("legend")

            legendMat.use_nodes = True
            t = legendMat.node_tree

            t.nodes.remove( t.nodes['Diffuse BSDF'] )

            emit = t.nodes.new( 'ShaderNodeEmission' )
            mo   = t.nodes['Material Output']

            # Link Emission to Material Output
            t.links.new( emit.outputs['Emission'], mo.inputs['Surface'] )

            # Generate new color ramp and link to Emission node
            colorRamp = t.nodes.new( 'ShaderNodeValToRGB' )
            t.links.new( emit.inputs['Color'], colorRamp.outputs['Color'] )

            # Add another color swatch in the middle of the ramp
            colorRamp.color_ramp.elements.new( 0.5 )

            # Set color ramp colors
            originalRampColors = obj.active_material.node_tree.nodes['ColorRamp'].color_ramp.elements[:]
            for i, c in enumerate( originalRampColors ):
                color = c.color[:]
                colorRamp.color_ramp.elements[i].color = color

            # Add Texture coordiantes and Mapping nodes
            mapp  = t.nodes.new( 'ShaderNodeMapping'  )
            texco = t.nodes.new( 'ShaderNodeTexCoord' )

            # Set up texture coordiantes Y rotation
            mapp.rotation[1] = radians( 45 )

            # Set up links
            t.links.new( mapp.inputs['Vector'],   texco.outputs['Object'] )
            t.links.new( colorRamp.inputs['Fac'], mapp.outputs['Vector'] )

        else:
            legendMat = bpy.data.materials["legend"]

        legendPlane.active_material = legendMat

    ## Generate legend text

    legendTextMat = None
    if 'legendText' in bpy.data.materials:
        legendTextMat = bpy.data.materials["legendText"]
    else:
        # Generate a material for the text
        legendTextMat = bpy.data.materials.new( "legendText" )

        legendTextMat.use_nodes = True
        t = legendTextMat.node_tree
        if 'Diffuse BSDF' in t.nodes: 
            t.nodes.remove( t.nodes['Diffuse BSDF'] )

        emit = t.nodes.new( 'ShaderNodeEmission' )
        mo   = t.nodes['Material Output'] if 'Material Output' in t.nodes else t.nodes.new( 'ShaderNodeOutputMaterial' )
        t.links.new( emit.outputs['Emission'], mo.inputs['Surface'] )
        emit.inputs['Color'].default_value = (0,0,0,1) # Set color to black

    # Calculate text positions
    heightRange = maxZ - minZ
    rungs       = 7
    interval    = heightRange / rungs

    ladderText = [ str( round( minZ + i * interval - offset, 2 ) ) for i in range(2, rungs) ]
    ladderText = [ str( round( minZ - offset, 2 ) ) ] + ladderText + [ str( round( maxZ - offset, 2 ) ) ] # Add min and max Z values

    legendGlobCoo = [ legendPlane.matrix_world * v.co for v in legendPlane.data.vertices ]
    legendY = [ co.y for co in legendGlobCoo ]

    minY, maxY = ( min( legendY ), max( legendY ) )
    yInterval  = ( maxY - minY ) / rungs
    yPositions = [ minY + i * yInterval for i in range( rungs ) ]

    # Set X position as legend plane's maximum X + a space of 0.5 blender units
    xPos = max([ co.x for co in legendGlobCoo ]) + 0.5

    for i, yPos, text in zip( range(rungs), yPositions, ladderText ):
        name = "rung%s" % i

        o = None
        if name in bpy.data.objects:
            o = bpy.data.objects[ name ]
        else:
            bpy.ops.object.text_add( location = ( xPos, yPos, 0 ), layers = [ i == 1 for i in range(20) ] )
            o = bpy.data.objects[ bpy.context.object.name ]
            o.name = name
            o.location.y += i * ( o.dimensions.y / 2 )

        o.data.body = text

        o.active_material = legendTextMat

bpy.app.handlers.frame_change_pre.append( update_legend )


EDITED:

Fixed the issue that occurred when running this script with a modified mesh (in this case with dynamic paint), by converting the modified object to a mesh and using its coordinates. Here's an image of the legend generated at frame 110 of your simulation:

EDITED2:

Now updates values according to current frame via an app_handler.

EDITED3:

corrected line 128 > range(1,rungs) to range(2,rungs), so legend of scale bar is correct