madrona.features - Spatial Content Management of Features

The madrona.features app works along with other Madrona apps to create a system that is best described as a content management system for user-designed spatial features. This system can be configured quickly to support a range of management options such as marine protected areas, hydrokinetic generators, wind turbines, or undersea cables. With one model definition it is possible to define the data schema for storing these features, as well as what behaviors and actions they support within the Madrona interface. A high degree of customization can be achieved with a Madrona project with this declarative format, without having to customize the view or client-side javascript components.

Feature Classes can be configured to:

  • Represent various management scenarios as Point, LineString or Polygon data
  • Collect attributes from users using forms generated from the model definition (or customized forms)
  • Pre-process and validate user-defined geometries with Manipulators
  • Enable sharing of features among users
  • Add custom downloads, like Shapefile or Excel files
  • Support custom editing actions

In addition, FeatureCollection Classes can be created that are collections of Feature Class instances with their own attributes. These can be used to represent simple Folders to help users organize their designs, or represent management concepts such as Marine Protected Area Networks.

Creating a Spatial Feature Class

Lets walk through the basics of creating a simple Feature Class. The basic process involves:

  • Defining a subclass of PointFeature, LineStringFeature, PolygonFeature, including the attributes to be stored with it.
  • Creating an Options inner-class, and using it to specify a form to use when creating or editing this Feature Class.
  • Creating kml and kml_style properties that define its KML representation
  • Specifying links to downloads or services related to the Feature Class.
  • Specifying any optional parameters on the Options inner-class
  • Creating a template to use when displaying this Feature Class’ attributes

Look at this example:

from madrona.features import register
from madrona.features.models import PolygonFeature
from madrona.features.forms import FeatureForm

@register
class Mpa(PolygonFeature):
    ext = models.CharField(max_length="12")

    class Options:
        verbose_name = 'Marine Protected Area'
        form = 'myproject.forms.MpaForm'
        links = (
            alternate('Shapefile',
                'mlpa.views.shapefile',
                select='single',
                type='application/shapefile'),

            alternate('KMZ (Google Earth)',
                'mlpa.views.kml_export',
                select='single multiple',
                type='application/vnd.google-earth.kmz',
                generic=True),

            related('MPA Spreadsheet',
                'mlpa.views.spreadsheet',
                select='single',
                type='application/excel'),

            edit('Delete w/Grids',
                'mlpa.views.delete_w_grids',
                confirm="Are you sure you want to delete with grids?",
                select="single multiple",
                args=[MpaArray],
                kwargs={'keyword_argument': True}),

            edit_form('Tags',
                'mlpa.views.tag',
                select='single multiple',
                generic=True,
                models=(MpaArray, MlpaMpa)),
        )

class MpaForm(FeatureForm):
    class Meta:
        model = Mpa

Defining the Model

Must be a subclass of one of the Feature subclasses (PointFeature, PolygonFeature, LineStringFeature)

Note

Keep the model name to under 30 characters in length. When creating a Feature model, django will automatically add permissions with a verbose name (e.g. “Can share Your Model Name”) which must be < 50 chars. Keeping the model name to around 30 chars or less will prevent SQL errors when creating the model.

Note

When creating a model for your unit tests, define the model outside of your TestCase class. Otherwise the feature class gets destroyed when the test finishes but it is never ‘unregistered’ which can lead to very difficult SQL/ORM debugging problems later in the tests.

Specifying a Form

All Feature Classes must have an Options inner-class that contains a property specifying the FeatureForm subclass that can be used to edit it. All other properties on the Options inner-class are optional.

Creating a “Show” Template

The show template is used to render sidebar content for a feature within the Madrona interface, and can also be used to render a printable and bookmarkable page for it. This template can be placed in any template directory by default under {{slug}}/show.html. Subdirectories are used to allow for overriding templates as mentioned in the django documentation. The default path to the show template can be changed using an optional show_template parameter to the Options inner-class.

Templates will be rendered with the following context:

  • instance - the feature class instance being being displayed

You can add to this list using the show_context Option property.

Customizing the Output Styling and KML Representation

There are three primary visual representations of Features: KML, the KMLTree and static maps. While the base Feature classes define reasonable default styling, it is likely that you’ll need to customize the look and feel for your implementation.

Customizing the styling of the KMLTree

You can use css to style the representation of the Features in the KMLTree, specifically the small icon to the left of the Feature name. There are two mechanisms to do this.

First you can specify an icon_url in the Options. This can be an absolute http URL or relative to the MEDIA_ROOT directory.

If you need more control over styling icons (such as specifying multiple styles or using scrolling sprites) you can use raw css by overriding the Feature.css() classmethod. For example:

@classmethod
def css(klass):
    return """
    li.KmlDocument > .icon {
      background: url('%(media)s/sprites/kml.png?1302821411') no-repeat -566px 0px ! important;
    }
    li.%(uid)s > .icon {
      background: url('%(media)s/sprites/kml.png?1302821411') no-repeat 0px 0px ! important;
    }
    """ % { 'uid': klass.model_uid(), 'media': settings.MEDIA_URL }

Beyond the Basics

Implementing a Custom Copy Method

Some default copying behavior is provided with the built-in feature.copy method. Unless you want to reimplement/change all that logic (and maybe your application requires it) you can call the Super() function and just override the necessary bits:

@register
class Folder(FeatureCollection):

    def copy(self, user):
        copy = super(Folder, self).copy(user)
        copy.name = copy.name.replace(' (copy)', '-Copy')
        copy.save()
        return copy

Specifying Manipulators

You must specify a list of required manipulators; if no manipulators are required simply pass an empty list []. Optional manipulators can be specified as well:

@register
class TestMpa(PolygonFeature):
    ...
    class Options:
        manipulators = [ 'madrona.manipulators.tests.TestManipulator' ]
        optional_manipulators = [ 'madrona.manipulators.manipulators.ClipToGraticuleManipulator' ]

Base Classes

Feature

class Feature(*args, **kwargs)

Model used for representing user-generated features

Attribute Description
user Creator
name Name of the object
date_created When it was created
date_modified When it was last updated.
add_to_collection(collection)

Add feature to specified FeatureCollection

copy(user=None)

Returns a copy of this feature, setting the user to the specified owner. Copies many-to-many relations

classmethod css(klass)

Specifies the CSS for representing features in kmltree, specifically the icon Works one of two ways: 1. Use the icon_url Option and this default css() classmethod 2. Override the css() classmethod for more complex cases

classmethod get_options(klass)

Returns model class Options object

hash

For caching. This string represents a hash of all attributes that may influence reporting results. i.e. if this property changes, reports for the feature get rerun.

is_viewable(user)

Is this feauture viewable by the specified user? Either needs to own it or have it shared with them. returns : Viewable(boolean), HttpResponse

kml_safe

A safety valve for kmlapp... If one feature’s .kml property fails, it won’t bring down the entire request. This property is never to be overridden!

classmethod model_uid(klass)

class method providing the uid for the model class.

remove_from_collection()

Remove feature from FeatureCollection

share_with(groups, append=False)

Share this feature with the specified group/groups. Owner must be a member of the group/groups. Group must have ‘can_share’ permissions else an Exception is raised

uid

Unique identifier for this feature.

Spatial Feature

class SpatialFeature(*args, **kwargs)

Abstract Model used for representing user-generated geometry features. Inherits from Feature and adds geometry-related methods/properties common to all geometry types.

Attribute Description
user Creator
name Name of the object
date_created When it was created
date_modified When it was last updated.
manipulators List of manipulators to be applied when geom is saved.
active_manipulators

This method contains all the logic to determine which manipulators get applied to a feature

If self.manipulators doesnt exist or is null or blank,
apply the required manipulators (or the NullManipulator if none are required)
If there is a self.manipulators string and there are optional manipulators contained in it,
apply the required manipulators PLUS the specified optional manipulators
geom_kml

Basic KML representation of the feature geometry

kml

Fully-styled KML placemark representation of the feature. The Feature’s kml property MUST

  • return a string containing a valid KML placemark element
  • the placemark must have id= [the feature’s uid]
  • if it references any style URLs, the corresponding Style element(s) must be provided by the feature’s .kml_style property
kml_style

Must return a string with one or more KML Style elements whose id’s may be referenced by relative URL from within the feature’s .kml string In any given KML document, each unique kml_style string will get included so don’t worry if you have 10 million features with “blah-default” style... only one will appear in the final document and all the placemarks can refer to it. BEST TO TREAT THIS LIKE A CLASS METHOD - no instance specific vars.

classmethod mapnik_style()

Mapnik style object containing rules for symbolizing features in staticmap

PointFeature

class PointFeature(*args, **kwargs)

Model used for representing user-generated point features. Inherits from SpatialFeature.

Attribute Description
user Creator
name Name of the object
date_created When it was created
date_modified When it was last updated.
manipulators List of manipulators to be applied when geom is saved.
geometry_original Original geometry as input by the user.
geometry_final Geometry after manipulators are applied.

LineStringFeature

class LineFeature(*args, **kwargs)

Model used for representing user-generated linestring features. Inherits from SpatialFeature.

Attribute Description
user Creator
name Name of the object
date_created When it was created
date_modified When it was last updated.
manipulators List of manipulators to be applied when geom is saved.
geometry_original Original geometry as input by the user.
geometry_final Geometry after manipulators are applied.

PolygonFeature

class PolygonFeature(*args, **kwargs)

Model used for representing user-generated polygon features. Inherits from SpatialFeature.

Attribute Description
user Creator
name Name of the object
date_created When it was created
date_modified When it was last updated.
manipulators List of manipulators to be applied when geom is saved.
geometry_original Original geometry as input by the user.
geometry_final Geometry after manipulators are applied.
centroid_kml

KML geometry representation of the centroid of the polygon

FeatureCollection Base Class

Subclasses of FeatureCollection have a one-to-many relationship with one or more Feature Classes. One could create a Marine Protected Area Network class that can only contain MPAs, or a Folder class that can contain any combination of FeatureClasses or even other Folders and FeatureCollections.

One important note about the sharing behavior of FeatureCollections - If a user shares a collection, all the features/collections contained within it are implicitly shared.

class MPANetwork(FeatureCollection):
    class Options:
        valid_children = ('mlpa.models.Mpa', )
class FeatureCollection(*args, **kwargs)

A Folder/Collection of Features

add(f)

Adds a specified Feature to the Collection

copy(user=None)

Returns a copy of this feature collection, setting the user to the specified owner. Recursively copies all children.

delete(*args, **kwargs)

Delete all features in the set

feature_set(recurse=False, feature_classes=None)

Returns a list of Features belonging to the Collection Optionally recurse into all child containers or limit/filter for a list of feature classes

remove(f)

Removes a specified Feature from the Collection

The Options inner-class

form(required)

Specifies a ModelForm that will be used to create and edit features of this class. The form must be a subclass of madrona.features.forms.FeatureForm, and the path to the form must be provided as a string. Otherwise you’ll cause circular reference issues.

verbose_name

Provide your feature class with a human readable name to be used within the interface. For example, this name determines the name used in the “Create” menu. If not specified, the CamelCase model name will be used. Even though it is optional, this property is obviously highly recommended.

icon_url

Provide the path to an icon image to represent the feature, both in the menu and the tree view. Path can be an absolute http URL or relative to the MEDIA_ROOT directory.

show_template

By default, will look for the template at {{modelname}}/show.html when rendering shape attributes. For example, the template for a model named MpaArray would be mpaarray/show.html. You can specify a different template location with this option.

form_template

Use this option to specify a custom template to be shown when creating or editing a feature. By default, looks for a template under features/form.html.

form_context

Specify a base context to use for rendering templates when creating and editing features.

show_context

Specify a base context to use when rendering feature attributes.

copy

Enabled by default, set to False to disable copy functionality. Calls the copy method of Feature, which can be overriden by subclasses to customize this functionality.

manipulators

Defaults to clipping features to the study region. Set to [] to disable.

optional_manipulators

Optional list of manipulators that users can choose to apply to any digitized features.

Specify links associated a Feature Class that point to related downloads, export tools, and editing actions that can be performed.

export_png

Specify if the PNG link will be created for this Feature. Default is False.