holoviz-topics / EarthSim

Tools for working with and visualizing environmental simulations.
https://earthsim.holoviz.org
BSD 3-Clause "New" or "Revised" License
65 stars 21 forks source link

Panelizing visualizing_meshes #254

Closed kcpevey closed 5 years ago

kcpevey commented 5 years ago

I'm trying to take the Visualizing_Meshes.ipynb and use panel to add tools to the San Diego error animation cell. My ultimate goal is figure out how to use the param widgets to affect the map.

fpath = '../data/SanDiego_Mesh/SanDiego.3dm'
tris, verts = read_3dm_mesh(fpath, skiprows=2)

fpath = '../data/SanDiego_Mesh/SanDiego_error.dat'
dfs = read_mesh2d(fpath)

fpath2 = '../data/SanDiego_Mesh/SanDiego_dep.dat'
dfs2 = read_mesh2d(fpath2)

#combine the two
for key, value in dfs.items():
    dfs[key] = pd.concat([dfs[key], dfs2[key]], axis=1)

internal_names = list(dfs[0])
label='Depth'

points = gv.operation.project_points(gv.Points((verts.x, verts.y), crs=ccrs.UTM(11)))

def time_mesh(time):
    depth_points = points.add_dimension(label, 0, dfs[time][label].values, vdim=True)
    return gv.TriMesh((tris, depth_points), crs=ccrs.GOOGLE_MERCATOR)

meshes = hv.DynamicMap(time_mesh, kdims='Time', label=label).redim.values(Time=sorted(dfs.keys()))
%%opts Image [colorbar=True] (cmap=cm_n['rainbow_r'])
%output holomap='scrubber' fps=4

class cmap_opts(param.Parameterized):
    colorcet_opts = {'Rainbow': cc.rainbow}
    colormap = param.ObjectSelector(default=colorcet_opts['Rainbow'], objects=colorcet_opts)

class display_range(param.Parameterized):
    color_range = param.Range(default=(-0.3, 0.3), bounds=(-0.3, 0.3))

class results(param.Parameterized):

    display_result = param.ObjectSelector(default=internal_names[0], objects=internal_names)

tiles = gv.WMTS('https://maps.wikimedia.org/osm-intl/{Z}/{X}/{Y}@2x.png')    
error_meshes = rasterize(meshes, aggregator=ds.mean(label))

map_pane = tiles * error_meshes.redim.range(HYDRO_ERROR=(-0.3, 0.3))
display_tab = pn.Column(display_range(name=''), cmap_opts(name=''), name='Display')
tab_pane = Tabs(('Results', results(name='')),
                ('Display', display_tab))
pn.Row(map_pane, tab_pane)

Which looks like this:
screen shot 2018-10-17 at 1 33 06 pm

Not bad for a first go, but it needs work.

  1. Why did I lose my colorbar/how do I get it back?
  2. Why did I lose the nifty animation tool and now I'm left with a Time slider?
  3. How do I switch redim.range(HYDRO_ERROR=-0.3, 0.3 to be able to feed it a variable (Philipp has definitely told me this answer before I can't find it.
  4. How do I connect my display_result widget with the label variable such that it will update the map when I change it?
kcpevey commented 5 years ago

4b. Same goes for the color_range and colormap widgets in the Display tab

kcpevey commented 5 years ago

geo_opts = dict(width=300, height=300). .options(**geo_opts)

kcpevey commented 5 years ago

I was hoping you'd go ahead and comment those notes you had during the meeting last week :) Or were going to write up an example?

kcpevey commented 5 years ago

Also, this issue https://github.com/pyviz/panel/issues/114 is related as I'm trying to correctly implement panel here. I'm having trouble accessing the visualized widget (I can change it, but when I access it programmatically, it appears unchanged). The way that you modified my solve code makes me think I need Pane in some way, but I'm not sure.

kcpevey commented 5 years ago

@philippjfr I'm passing this to @JoshuaQChurch . Could you write a quick code snippet on what we discussed in the meeting on Thursday showing the `hv.DynamicMap, the callback function, and how that would fit into this example?

kcpevey commented 5 years ago

@philippjfr any advice here?

philippjfr commented 5 years ago

Will get to this first thing tomorrow, am out after a tooth extraction today.

philippjfr commented 5 years ago

Here's what I've come up with:

from earthsim import parameters
from holoviews.streams import Params

points = gv.operation.project_points(gv.Points((verts.x, verts.y), crs=ccrs.UTM(11)))

# Create a parameterized class to select between ERROR and Depth
results = parameters(display_result=param.ObjectSelector(default=internal_names[0], objects=internal_names))

# Define callback which returns TriMesh for specific time and ERROR/Depth
def time_mesh(time, display_result):
    depth_points = points.add_dimension(display_result, 0, dfs[time][display_result].values, vdim=True)
    return gv.TriMesh((tris, depth_points), label=label, crs=ccrs.GOOGLE_MERCATOR)

# Declare DynamicMap which varies by time and is linked to results class
meshes = hv.DynamicMap(time_mesh, kdims='Time', streams=[Params(results)]).redim.values(Time=sorted(dfs.keys()))

# Declare classes to control colormap and display range
cmap_opts = parameters(colormap=param.ObjectSelector(default=cc.rainbow, objects={'Rainbow': cc.rainbow}))
display_range = parameters(color_range=param.Range(default=(-0.3, 0.3), bounds=(-0.3, 0.3)))

# Define function which applies colormap and color_range
def apply_opts(obj, colormap, color_range):
    return obj.options(cmap=colormap).redim.range(**{obj.vdims[0].name: color_range})

# Apply the colormap and color range dynamically
dynamic = hv.util.Dynamic(rasterize(meshes), operation=apply_opts, streams=[Params(cmap_opts), Params(display_range)])

# Display everything as a Panel
hv_panel = pn.panel(dynamic)
pn.Row(hv_panel[0], pn.Column(hv_panel[1], cmap_opts, display_range, results))
screen shot 2018-11-01 at 12 23 15 pm
kcpevey commented 5 years ago

Thank you so much!! I hope you get to feeling better soon!

kcpevey commented 5 years ago

I confirmed that the colormap picker works for me with this example. I'm fairly certain its a bug in my code that I'm still trying to track down.

kcpevey commented 5 years ago

I figured out my colormap bug. I'm opening another issue for it.

philippjfr commented 5 years ago

Great, hope it wasn't too much of a pain to figure out.

kcpevey commented 5 years ago

This working for me. I'll go ahead and close, but I still think it would make a good addition to the docs :)