The colors that are used in graphs
COLORS_DEFAULT = [
{'mapnik': 'blue', 'display_name': _('blue')},
{'mapnik': 'magenta', 'display_name': _('magenta')},
{'mapnik': 'yellow', 'display_name': _('yellow')},
{'mapnik': 'black', 'display_name': _('black')},
{'mapnik': 'cyan', 'display_name': _('cyan')},
{'mapnik': 'red', 'display_name': _('red')},
{'mapnik': 'lightblue', 'display_name': _('lightblue')},
{'mapnik': 'grey', 'display_name': _('grey')},
]
save workspaces to session
def save_workspaces(self):
workspace_group_ids = {} for group, workspace_list in self.workspaces.items():
workspace_group_ids[group] = [workspace.id for workspace in workspace_list] self.request.session['workspaces'] = workspace_group_ids logger.debug('WorkspaceManager.save_workspaces: saved ' 'workspace_group_ids in session.')def load_workspaces(self, workspace_group_ids=None): load workspaces from session
note: request.session['workspaces'] must be filled before
using this function
returns number of workspaces that could not be loaded"""
errors = 0
if workspace_group_ids is None:
if 'workspaces' in self.request.session:
workspace_group_ids = self.request.session['workspaces']
else:
logger.warn(('WorkspaceManager.load_workspaces: no workspaces'
' in kwargs or in session.'))
return 1
#DIVIDER
for group, workspace_ids in workspace_group_ids.items():
self.workspaces[group] = []
for workspace_id in workspace_ids:
try:
new_workspace = Workspace.objects.get(pk=workspace_id)
self.workspaces[group].append(new_workspace)
except Workspace.DoesNotExist:
errors += 1
return errors
#DIVIDER
for workspace in self.workspaces[category]:
workspace.workspace_items.all().delete()
#DIVIDER
def load_or_create(self, new_workspace=False):
#DIVIDER
self.workspaces = {}
changes = False
if 'workspaces' in self.request.session:
changes = self.load_workspaces()
#DIVIDER
if not DEFAULT_WORKSPACES in self.workspaces:
try:
self.workspaces[DEFAULT_WORKSPACES] = [
Workspace.objects.get(name='achtergrond')]
#DIVIDER
except Workspace.DoesNotExist:
pass
changes = True
if (not TEMP_WORKSPACES in self.workspaces or
not self.workspaces[TEMP_WORKSPACES]):
workspace_temp = Workspace(name=TEMP_WORKSPACES)
workspace_temp.save()
self.workspaces[TEMP_WORKSPACES] = [workspace_temp]
changes = True
if (new_workspace or
not USER_WORKSPACES in self.workspaces or
not len(self.workspaces[USER_WORKSPACES])):
workspace_user = Workspace()
workspace_user.save()
self.workspaces[USER_WORKSPACES] = [workspace_user]
changes = True
#DIVIDER
if len(self.workspaces[USER_WORKSPACES][0].collages.all()) == 0:
self.workspaces[USER_WORKSPACES][0].collages.create()
if changes:
self.save_workspaces()
return self.workspaces
#DIVIDER
def _in_collection(self, workspace):
#DIVIDER
for group, workspaces in self.workspaces.items():
if workspace in workspaces:
return True
return False
#DIVIDER
def add_other(self, workspace_id):
#DIVIDER
class WorkspaceItemAdapter(object):
#DIVIDER
layer_arguments = {}
is_animatable = False
allow_custom_legend = False
#DIVIDER
def layer(self, layer_ids=None, request=None):
#DIVIDER
raise NotImplementedError
#DIVIDER
def extent(self, identifiers=None):
#DIVIDER
def search(self, x, y, radius=None):
#DIVIDER
raise NotImplementedError
#DIVIDER
def value_aggregate(self, identifier, aggregate_functions,
start_date=None, end_date=None):
#DIVIDER
def values(self, identifier, start_date, end_date):
#DIVIDER
raise NotImplementedError
#DIVIDER
def value_aggregate_default(self, identifier, aggregate_functions,
start_date, end_date):
#DIVIDER
if key == 'min':
result_value = min(values_only)
elif key == 'max':
result_value = max(values_only)
elif key == 'avg':
result_value = float(sum(values_only)) / len(values_only)
elif key == 'count_lt':
if value is None:
result_value = None
else:
result_value = 0
for v in values_only:
if v < value: # value is boundary value
result_value += 1
elif key == 'count_gte':
if value is None:
result_value = None
else:
result_value = 0
for v in values_only:
if v >= value: # value is boundary value
result_value += 1
elif key == 'percentile':
if value is None:
result_value = None
else:
rank = int(value * len(values_only) / 100.0 + 0.5)
result_value = values_only[rank]
else:
result_value = None
except (ValueError, IndexError, TypeError, ZeroDivisionError):
result_value = None
result[key] = result_value
return result
#DIVIDER
def location(self, identifier=None, layout=None):
#DIVIDER
raise NotImplementedError
#DIVIDER
def line_styles(self, identifiers):
#DIVIDER
def image(self, identifiers=None, start_date=None, end_date=None,
width=None, height=None, layout_extra=None):
#DIVIDER
raise NotImplementedError
#DIVIDER
def symbol_url(self, identifier=None, start_date=None, end_date=None,
icon_style=None):
#DIVIDER
sm = SymbolManager(ICON_ORIGINALS, os.path.join(
settings.MEDIA_ROOT,
'generated_icons'))
if icon_style is None:
icon_style = {'icon': 'empty.png'}
output_filename = sm.get_symbol_transformed(icon_style['icon'],
**icon_style)
return settings.MEDIA_URL + 'generated_icons/' + output_filename
#DIVIDER
def html(self, snippet_group=None, identifiers=None, layout_options=None):
#DIVIDER
def html_default(self, snippet_group=None, identifiers=None,
layout_options=None, template=None,
extra_render_kwargs=None):
#DIVIDER
if snippet_group:
#DIVIDER
img_url = reverse(
"lizard_map.snippet_group_image",
kwargs={'snippet_group_id': snippet_group.id},
)
else:
#DIVIDER
img_url = reverse(
"lizard_map.workspace_item_image",
kwargs={'workspace_item_id': self.workspace_item.id},
)
#DIVIDER
if legend:
for identifier in identifiers:
if not 'layout' in identifier:
identifier['layout'] = {}
identifier['layout']['legend'] = True
identifiers_escaped = [json.dumps(identifier).replace('"', '%22')
for identifier in identifiers]
img_url = img_url + '?' + '&'.join(['identifier=%s' % i for i in
identifiers_escaped])
#DIVIDER
display_group = [self.location(**identifier) for identifier in
identifiers]
if template is None:
template = 'lizard_map/popup.html'
render_kwargs = {
'title': title,
'display_group': display_group,
'img_url': img_url,
'symbol_url': self.symbol_url(),
'add_snippet': add_snippet,
'editing': editing,
'snippet_group': snippet_group,
'colors': COLORS_DEFAULT,
}
if extra_render_kwargs is not None:
render_kwargs.update(extra_render_kwargs)
return render_to_string(
template,
render_kwargs)
#DIVIDER
def legend(self, updates=None):
#DIVIDER
def legend_object_default(self, legend_name):
#DIVIDER
logger.warn("Could not find legend for key '%s', "
"please configure the legend. "
"Now using fallback (red).")
color = Color('ff0000')
found_legend = Legend(descriptor="", min_color=color,
max_color=color, too_low_color=color,
too_high_color=color)
return found_legend
#DIVIDER
def legend_default(self, legend_object):
Workspaces are grouped by key TEMP_WORKSPACES, USER_WORKSPACES, etc.
clear all items in workspace category
load workspaces references by session['workspaces'] or
create new workspace (saves in case of changes to workspaces)
workspaces are returned in a dictionary: { 'default': [...default layers], 'temp': workspace_temp, 'user': [...user workspaces] }
they are stored in the session as a dictionary of ids: { 'default': [id1, id2, ...], 'temp': [id, ], 'user': [id3, id4, ...], }
check if components exist, else create them
^^^ TODO: use non-Dutch name.
create collage if necessary, it is stored in the workspace
Check if given workspace is already in current collection.
Add a workspace in "other",
if the workspace is not already in your collection.
Sometimes you want to add workspaces from others
Base class for workspace_item adapters.
Lizard-map needs to display workspace items. Search in them according to clicks on the map. And so on. But workspace items can be anything. An adapter adapts a workspace item to what lizard-map needs.
So for every new kind of workspace item, you'll need a fresh adapter that subclasses this base adapter. And you'll need to implement the NotImplementedError'ed methods.
Generates and returns layers, styles.
Layers is a list of mapnik layers.
Styles is a list of mapnik styles (which are used in the layers).
Returns extent {'west':.., 'north':.., 'east':.., 'south':..} in google projection. None for each key means unknown.
Optional: If identifiers is given, return extent for those identifiers only.
Search by coordinates. Return list of dicts for matching
items.
{'distance':
Required: distance, name, workspace_item, google_coords Highly recommended (else some functions will not work): identifier (for popups)
Calculates aggregated values of identifier. Returns dict with aggregation function as key and value as value. {'avg': 3.5, 'min': 1, 'max': 6}.
The given functions in aggregate_functions will be calculated:
aggregate_functions = {
'avg': None,
'min': None,
'max': None,
'count_lt': 'percentile':
} all functions are optional.
Return values in list of dictionaries (datetime, value, unit)
Default implementation for value_aggregate.
Values are not always numbers - in case of strings this will result in a TypeError the sequence can be empty
Return fews point representation corresponding to filter_id,
location_id and parameter_id in same format as search function
layout is a dict with extra optional layout parameters: y_min, y_max, y_label, x_label, line_avg, line_max, line_min
{'object': <...>, 'google_x': x coordinate in google, 'google_y': y coordinate in google, 'workspace_item': <...>, 'identifier': {...}, 'grouping_hint': optional unique group identifier, i.e. unit m3/s}
Get line styles for given identifiers. For each set of identifiers, the line styles are calculated deterministic.
EXPERIMENTAL: this function can be used to generate a legend function, seperately of the image function.
Keys are str(identifiers). Values are dicts with properties 'color', 'linestyle', 'linewidth', 'max_linestyle', 'max_linewidth', 'min_linestyle', 'min_linewidth', ...
Return image of given parameters.
layout_extra can have the following parameters (all are optional):
'y_label' = value y_label
'x_label' = value x_label
'y_min' = value y_min
'y_max' = value self.layout_y_max
'title' = title
'horizontal_lines' = [{
'name': 'linestyle': '--',
'color': 'green'}, }]
'vertical_lines' = [{
'name':
Return symbol for identifier.
Implementation: respect the fact when icon_style is already given. If it's empty, generate own icon if applicable.
Html output for given identifiers. Optionally layout_options can be provided. Default layout_options:
layout_options = {'add_snippet': False,
'editing': False}
Returns html representation of given snippet_group OR identifiers (snippet_group has priority). If a snippet_group is provided, more options are available.
This particular view always renders a list of items, then 1 image
Use this function if html function behaviour is default: def html(self, identifiers):
return super(WorkspaceItemAdapterKrw, self).html_default( identifiers)
Image url: for snippet_group there is a special (dynamic) url.
Image url for snippet_group: can change if snippet_group properties are altered.
Image url: static url composed with all options and layout tweaks
If legend option: add legend to layout of identifiers
Make 'display_group'
Returns legend in a list of dictionaries. If this method returns a list, then the legend icon will appear in your workspace.
Dictionary = {'img_url':
updates: ...
Get legend object. If no appropriate legend was found, a legend object will be created and returned.
Fallback if no legend found (should not happen)
Default implementation for legend. A legend is displayed