Skip to content

Commit

Permalink
Heavy cleanup on Cell mapping to reflect #8.
Browse files Browse the repository at this point in the history
  • Loading branch information
philippkraft committed Jan 17, 2018
1 parent 57df484 commit e2ce445
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 144 deletions.
307 changes: 171 additions & 136 deletions cmf/draw/draw_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,72 +15,114 @@
#
# You should have received a copy of the GNU General Public License
# along with cmf. If not, see <http://www.gnu.org/licenses/>.
#
#
from __future__ import print_function, division, absolute_import
import pylab
import numpy
from cmf.cell_factory import geometry as geoms
import cmf.cell_factory
import os
from .. import cmf_core as cmf


class CellMap(pylab.matplotlib.cm.ScalarMappable):
"""
Draws a map of the cell geometries. Only functional, when shapely is installed.
A CellMap is created with cells to show and a function returning a value from a cell
class cell_polygon_map(pylab.matplotlib.cm.ScalarMappable):
def __call__(self,recalc_range=False):
Usage example:
>>>def saturated_depth(c):
... return c.saturated_depth
>>>cm = CellMap(project, saturated_depth)
"""
def __call__(self, recalc_range=False):
if recalc_range:
self.maxvalue=max((self.f(c) for c in self.polygons.iterkeys()))
self.minvalue=min((self.f(c) for c in self.polygons.iterkeys()))
for cell,poly in self.polygons.iteritems():
self.maxvalue=max((self.f(c) for c in self.cells))
self.minvalue=min((self.f(c) for c in self.cells))

for cell,polys in self.polygons.iteritems():
v=self.f(cell)
c=self.cmap((v-self.minvalue)/(self.maxvalue-self.minvalue))
poly.set_fc(c)
for poly in polys:
poly.set_fc(c)
if pylab.isinteractive():
pylab.draw()
pylab.draw()

@property
def f(self): return self.__f


@f.setter
def f(self,funct):
def f(self, funct):
self.__f=funct
if pylab.isinteractive():
self(True)

@property
def color_values(self):
return numpy.array([self.f(c) for c in self.cells])
def __init__(self,cells,value_function, cmap=pylab.cm.jet,hold=True,vmin=None,vmax=None,**kwargs):
self.cells=cells

@staticmethod
def draw_shapes(shape, c, **kwargs):
if hasattr(shape, "exterior"):
shape = shape.exterior
a = pylab.asarray(shape)
return pylab.fill(a[:, 0], a[:, 1], fc=c, **kwargs)[0]

def __init__(self, cells, value_function, cmap=pylab.cm.jet,
hold=True, vmin=None, vmax=None, **kwargs):
"""
:param cells:
:param value_function:
:param cmap:
:param hold:
:param vmin:
:param vmax:
:param kwargs:
"""

if not hasattr(cmf.Cell, 'geometry'):
raise NotImplementedError('The geometry of the cells can not be used, shapely is not installed')

self.cells=[c for c in cells if c.geometry]
self.__f = value_function
was_interactive=pylab.isinteractive()
if was_interactive: pylab.ioff()
geos=[]
self.maxvalue=-1e300 if vmax is None else vmax
self.minvalue=1e300 if vmin is None else vmin

was_interactive = pylab.isinteractive()

if was_interactive:
pylab.ioff()


self.polygons={}
# Generate image array, which is filled with generated values from self.f
self._A = []
for cell in cells:
shape=geoms[cell]

def flatten_multipolygons(shape):
if hasattr(shape, "geoms"):
shapes=shape.geoms
return shape.geoms
else:
shapes=[shape]
value=self.f(cell)
self._A.append(value)
if vmax is None:
self.maxvalue=max(value,self.maxvalue)
if vmin is None:
self.minvalue=min(value,self.minvalue)
for s in shapes:
geos.append((cell,s,value))
if self.minvalue>=self.maxvalue: self.minvalue=self.maxvalue-1
for cell,s,v in geos:
if hasattr(s, "exterior"):
s=s.exterior
c=cmap(float(v-self.minvalue)/float(self.maxvalue-self.minvalue))
a=pylab.asarray(s)
self.polygons[cell]=pylab.fill(a[:,0],a[:,1],fc=c,hold=hold,**kwargs)[0]
hold=1
return [shape]

geos = [flatten_multipolygons(c.geometry) for c in self.cells]
values = [self.f(c) for c in self.cells]
self.maxvalue = vmax or max(values)
self.minvalue = vmin or min(values)

if self.minvalue >= self.maxvalue:
self.minvalue = self.maxvalue-1

if not hold:
pylab.cla()

for cell, shapes, v in zip(self.cells, geos, values):

c = self.cmap(float(v-self.minvalue)/float(self.maxvalue-self.minvalue))
self.polygons[cell] = [self.draw_shapes(s, c, **kwargs) for s in shapes]

pylab.axis('equal')
norm = pylab.matplotlib.colors.Normalize(self.minvalue, self.maxvalue)
pylab.matplotlib.cm.ScalarMappable.__init__(self, norm, cmap)

if was_interactive:
pylab.draw()
pylab.draw()
pylab.ion()

def autoscale_None(self):
Expand All @@ -93,50 +135,42 @@ def autoscale(self):
Overwrite base class of maplotlib.cm.ScalarMappable to prevent missuse
"""
pass
# def callbacksSM(self):
# pass


def drawobjects(objects,style=None,hold=1,**kwargs):
was_interactive=pylab.isinteractive()
if was_interactive: pylab.ioff()
for i,o in enumerate(objects):
shape=geoms.get(o)
if hasattr(shape, "geoms"):
shapes=list(shape.geoms)
else:
shapes=[shape]
for s in shapes:
if hasattr(s, "exterior"):
s=s.exterior
a=pylab.array(s.coords)
if style is None:
pylab.plot(a[:,0],a[:,1],hold=hold,**kwargs)
else:
pylab.plot(a[:,0],a[:,1],style,hold=hold,**kwargs)
hold=1
pylab.axis('scaled')
if was_interactive:
pylab.draw()
pylab.ion()


def __x_from_ts(ts):
return pylab.fromiter(((t-cmf.Time(1,1,1))/cmf.day for t in ts.iter_time()),dtype=numpy.float)
def plot_timeseries(data,style='-',**kwargs):


def plot_timeseries(data,style='-',**kwargs):
"""
Plots a cmf.timeseries as a line using pylab.plot
:param data: cmf.timeseries
:param style: Style code for pylab.plot
:param kwargs: Keyword arguments for pylab.plot
:return: matplotlib line object
"""
try:
step = kwargs.pop('step')
ts = data.reduce_avg(data.begin - data.begin % step,step)
step = kwargs.pop('step')
ts = data.reduce_avg(data.begin - data.begin % step, step)
except KeyError:
ts=data
x=__x_from_ts(ts)
ts = data

x = __x_from_ts(ts)
line=pylab.plot(x,pylab.asarray(ts),style,**kwargs)[0]
ax=pylab.gca()
ax.xaxis_date()
return line


def bar_timeseries(data,**kwargs):
"""
Makes a bar graph from a cmf.timeseries using pylab.bar
:param data: cmf.timeseries
:param kwargs: Keyword arguments of pylab.bar
:return: as pylab.bar
"""
try:
step = kwargs.pop('step')
step = kwargs.pop('step')
ts = data.reduce_avg(data.begin - data.begin % step,step)
except KeyError:
ts=data
Expand All @@ -150,86 +184,87 @@ def bar_timeseries(data,**kwargs):
pylab.draw()
pylab.ion()
return bars



def plot_locatables(locatables,style='kx',**kwargs):
"""
Plots a sequence of objects with a position attribute
:param locatables:
:param style:
:param kwargs:
:return:
"""
get_x=lambda l:l.position.x
get_y=lambda l:l.position.y
pylab.plot(pylab.amap(get_x,locatables),pylab.amap(get_y,locatables),style,**kwargs)


def connector_matrix(allstates,size=(500,500)):
"""Returns a matrix
"""
posdict={}
jac=numpy.zeros(size,dtype=int)
jac=numpy.zeros(size, dtype=int)
l=len(allstates)
for i,a in enumerate( allstates):
posdict[a.node_id]=i
for i,a in enumerate( allstates):
for i,a in enumerate(allstates):
posdict[a.node_id] = i
for i,a in enumerate(allstates):
for f,t in a.fluxes(cmf.Time()):
j=posdict.get(t.node_id)
if j:
jac[i*size[0]/l,j*size[1]/l]+=1
return jac
jac[i*size[0]/l, j*size[1]/l] += 1
return jac


class FluxMap(object):
"""
Draws for each cell an arrow indicating the direction and velocity of flow
through the cell (in horizontal direction). Uses pylab.quiver
The FluxMap can be updated by calling it with the new timestep

class cell_quiver(object):
def __call__(self,t=None):
Usage:
>>> fm = FluxMap(project, cmf.Time())
>>> for t in solver.run(solver.t, solver.t + cmf.day * 30, cmf.h):
... fm(t)
"""
def __call__(self, t=None):
a = numpy.array
if t: self.t = t
f = cmf.cell_flux_directions(self.cells,self.t)
self.quiver.set_UVC(a(f.X),a(f.Y),self.color_array)
if pylab.isinteractive(): pylab.draw()
def __init__(self,cells,t,**kwargs):
if t:
self.t = t
f = cmf.cell_flux_directions(self.cells, self.t)

self.quiver.set_UVC(a(f.X), a(f.Y), self.color_array)

if pylab.isinteractive():
pylab.draw()

def __init__(self, cells, t, **kwargs):
"""
Creates a new flux map
:param cells: The cells to be used
:param t: The current time step
:param kwargs: Keyword arguments for pylab.quiver
"""
self.cells = cells
# get position vector
p = cmf.cell_positions(cells)
f = cmf.cell_flux_directions(cells,t)
self.color_array = None
self.t = t
# get flux vector
f = cmf.cell_flux_directions(cells, t)
self.t = t
a = numpy.array
self.quiver = pylab.quiver(a(p.X),a(p.Y),a(f.X),a(f.Y),**kwargs)
self.quiver = pylab.quiver(a(p.X), a(p.Y), a(f.X), a(f.Y), **kwargs)

def __get_scale(self):
return self.quiver.scale

def __set_scale(self,value):
self.quiver.scale = value
self()
scale = property(__get_scale,__set_scale)
class quiver3d(object):
def __init__(self,objects,t,zscale=1.0,**kwargs):
"""Invokes mlab.quiver3d. Mayavi 2 by Enthought has to be installed
objects: Either a cmf.node_list or a sequence of cells
t : A cmf.Time or a datetime.datetime object
keywords are passed to mlab.quiver3d
"""
try:
from enthought.mayavi import mlab
from numpy import asarray, meshgrid
except ImportError:
raise NotImplementedError("Raster.draw3d needs an installation of mayavi to work")
if isinstance(objects,cmf.node_list):
p=objects.get_positions()
f=objects.get_fluxes3d(t)
elif isinstance(objects,cmf.project):
p=cmf.cell_positions(objects.cells)
f=cmf.cell_fluxes(objects.cells,t)
elif isinstance(objects[0],cmf.Cell):
p=cmf.cell_positions(objects)
f=cmf.cell_fluxes(objects,t)
else:
raise ValueError("Given objects are not a nodelist or a sequence of cells")
self.objects = objects
self.zscale = zscale
self.quiver = mlab.quiver3d(p.X,p.Y,p.Z,f.X,f.Y,f.Z*zscale,**kwargs)
def __call__(self,t):
if isinstance(self.objects,cmf.node_list):
f=self.objects.get_fluxes3d(t)
elif isinstance(self.objects,cmf.project):
f=cmf.cell_fluxes(self.objects.cells,t)
elif isinstance(self.objects[0],cmf.Cell):
f=cmf.cell_fluxes(objects,t)
else:
raise ValueError("Given objects are not a nodelist or a sequence of cells")
self.quiver.mlab_source.set(u=f.X,v=f.Y,w=f.Z*self.zscale)


scale = property(__get_scale, __set_scale)




try:
Expand All @@ -248,11 +283,11 @@ def plot_image(filename,**kwargs):
right = left + world[0] * image.size[0]
return pylab.imshow(image,extent=(left,right,bottom,top),origin='bottom',**kwargs)
else:
print "File",filename,"or worldfile",worldname,"not found"
print("File", filename, "or worldfile", worldname, "not found")
except:
pass


def contour_raster(raster,**kwargs):
Z=raster.asarray()
Z=numpy.flipud(Z)
Expand All @@ -268,5 +303,5 @@ def contourf_raster(raster,**kwargs):
C=pylab.contourf(Z,extent=extent,**kwargs)
pylab.clabel(C)
pylab.axis('scaled')

Loading

0 comments on commit e2ce445

Please sign in to comment.