<commit_before># -*- coding: utf-8 -*-
import re
import os
from math import isnan
import logging
from datetime import datetime
import functools

from django.contrib.gis.db import models
from django.db import connection
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.contrib.gis.geos import LineString, Point

import pygal
from pygal.style import LightSolarizedStyle
from mapentity.models import MapEntityMixin
from mapentity.helpers import is_file_newer, convertit_download

from geotrek.authent.models import StructureRelated
from geotrek.common.models import TimeStampedModel, NoDeleteMixin
from geotrek.common.utils import classproperty, sampling

from .helpers import PathHelper, TopologyHelper


logger = logging.getLogger(__name__)


class AltimetryMixin(models.Model):
    # Computed values (managed at DB-level with triggers)
    length = models.FloatField(editable=False, default=0.0, null=True, blank=True, db_column='longueur', verbose_name=_(u"Length"))
    ascent = models.IntegerField(editable=False, default=0, null=True, blank=True, db_column='denivelee_positive', verbose_name=_(u"Ascent"))
    descent = models.IntegerField(editable=False, default=0, null=True, blank=True, db_column='denivelee_negative', verbose_name=_(u"Descent"))
    min_elevation = models.IntegerField(editable=False, default=0, null=True, blank=True, db_column='altitude_minimum', verbose_name=_(u"Minimum elevation"))
    max_elevation = models.IntegerField(editable=False, default=0, null=True, blank=True, db_column='altitude_maximum', verbose_name=_(u"Maximum elevation"))
    slope = models.FloatField(editable=False, null=True, blank=True, default=0.0, verbose_name=_(u"Slope"), db_column='pente')

    COLUMNS = ['length', 'ascent', 'descent', 'min_elevation', 'max_elevation', 'slope']

    class Meta:
        abstract = True

    def get_elevation_profile(self):
        """
        Extract elevation profile from geom.
        """
        return AltimetryMixin.elevation_profile(self.geom)

    def get_elevation_profile_svg(self):
        """
        Plot the altimetric graph in SVG using PyGal.
        Most of the job done here is dedicated to preparing
        nice labels scales.
        """
        profile = self.get_elevation_profile()
        distances = [v[0] for v in profile]
        elevations = [v[3] for v in profile]
        min_elevation = int(min(elevations))
        floor_elevation = min_elevation - min_elevation % 10
        max_elevation = int(max(elevations))
        ceil_elevation = max_elevation + 10 - max_elevation % 10

        x_labels = distances
        y_labels = [min_elevation] + sampling(range(floor_elevation + 20, ceil_elevation - 10, 10), 3) + [max_elevation]

        config = dict(show_legend=False,
                      print_values=False,
                      show_dots=False,
                      x_labels_major_every=int(len(profile)/2),
                      show_minor_x_labels=False,
                      width=800,
                      height=400,
                      title_font_size=25,
                      label_font_size=20,
                      major_label_font_size=25,
                      js=[])

        style = LightSolarizedStyle
        style.background = 'white'
        style.colors = ('#5393E8',)
        line_chart = pygal.StackedLine(fill=True, style=style, **config)
        line_chart.x_title = unicode(_("Distance (m)"))
        line_chart.x_labels = [str(i) for i in x_labels]
        line_chart.y_title = unicode(_("Altitude (m)"))
        line_chart.y_labels = [str(i) for i in y_labels]
        line_chart.range = [floor_elevation, max_elevation]
        line_chart.add('', elevations)
        return line_chart.render()

    @models.permalink
    def get_elevation_chart_url(self):
        """Generic url. Will fail if there is no such url defined
        for the required model (see core.Path and trekking.Trek)
        """
        app_name = self._meta.app_name
        model_name = self._meta.module_name
        return ('%s:%s_profile_svg' % (app_name, model_name), [str(self.pk)])

    def get_elevation_chart_path(self):
        """Path to the PNG version of elevation chart.
        """
        basefolder = os.path.join(settings.MEDIA_ROOT, 'profiles')
        if not os.path.exists(basefolder):
            os.mkdir(basefolder)
        return os.path.join(basefolder, '%s-%s.png' % (self._meta.module_name, self.pk))

    def prepare_elevation_chart(self, request):
        """Converts SVG elevation URI to PNG on disk.
        """<commit_msg>Fix generic URL generation for SVG altimetric profiles<commit_after># -*- coding: utf-8 -*-
import re
import os
from math import isnan
import logging
from datetime import datetime
import functools

from django.contrib.gis.db import models
from django.db import connection
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.contrib.gis.geos import LineString, Point

import pygal
from pygal.style import LightSolarizedStyle
from mapentity.models import MapEntityMixin
from mapentity.helpers import is_file_newer, convertit_download

from geotrek.authent.models import StructureRelated
from geotrek.common.models import TimeStampedModel, NoDeleteMixin
from geotrek.common.utils import classproperty, sampling

from .helpers import PathHelper, TopologyHelper


logger = logging.getLogger(__name__)


class AltimetryMixin(models.Model):
    # Computed values (managed at DB-level with triggers)
    length = models.FloatField(editable=False, default=0.0, null=True, blank=True, db_column='longueur', verbose_name=_(u"Length"))
    ascent = models.IntegerField(editable=False, default=0, null=True, blank=True, db_column='denivelee_positive', verbose_name=_(u"Ascent"))
    descent = models.IntegerField(editable=False, default=0, null=True, blank=True, db_column='denivelee_negative', verbose_name=_(u"Descent"))
    min_elevation = models.IntegerField(editable=False, default=0, null=True, blank=True, db_column='altitude_minimum', verbose_name=_(u"Minimum elevation"))
    max_elevation = models.IntegerField(editable=False, default=0, null=True, blank=True, db_column='altitude_maximum', verbose_name=_(u"Maximum elevation"))
    slope = models.FloatField(editable=False, null=True, blank=True, default=0.0, verbose_name=_(u"Slope"), db_column='pente')

    COLUMNS = ['length', 'ascent', 'descent', 'min_elevation', 'max_elevation', 'slope']

    class Meta:
        abstract = True

    def get_elevation_profile(self):
        """
        Extract elevation profile from geom.
        """
        return AltimetryMixin.elevation_profile(self.geom)

    def get_elevation_profile_svg(self):
        """
        Plot the altimetric graph in SVG using PyGal.
        Most of the job done here is dedicated to preparing
        nice labels scales.
        """
        profile = self.get_elevation_profile()
        distances = [v[0] for v in profile]
        elevations = [v[3] for v in profile]
        min_elevation = int(min(elevations))
        floor_elevation = min_elevation - min_elevation % 10
        max_elevation = int(max(elevations))
        ceil_elevation = max_elevation + 10 - max_elevation % 10

        x_labels = distances
        y_labels = [min_elevation] + sampling(range(floor_elevation + 20, ceil_elevation - 10, 10), 3) + [max_elevation]

        config = dict(show_legend=False,
                      print_values=False,
                      show_dots=False,
                      x_labels_major_every=int(len(profile)/2),
                      show_minor_x_labels=False,
                      width=800,
                      height=400,
                      title_font_size=25,
                      label_font_size=20,
                      major_label_font_size=25,
                      js=[])

        style = LightSolarizedStyle
        style.background = 'white'
        style.colors = ('#5393E8',)
        line_chart = pygal.StackedLine(fill=True, style=style, **config)
        line_chart.x_title = unicode(_("Distance (m)"))
        line_chart.x_labels = [str(i) for i in x_labels]
        line_chart.y_title = unicode(_("Altitude (m)"))
        line_chart.y_labels = [str(i) for i in y_labels]
        line_chart.range = [floor_elevation, max_elevation]
        line_chart.add('', elevations)
        return line_chart.render()

    @models.permalink
    def get_elevation_chart_url(self):
        """Generic url. Will fail if there is no such url defined
        for the required model (see core.Path and trekking.Trek)
        """
        app_label = self._meta.app_label
        model_name = self._meta.module_name
        return ('%s:%s_profile_svg' % (app_label, model_name), [str(self.pk)])

    def get_elevation_chart_path(self):
        """Path to the PNG version of elevation chart.
        """
        basefolder = os.path.join(settings.MEDIA_ROOT, 'profiles')
        if not os.path.exists(basefolder):
            os.mkdir(basefolder)
        return os.path.join(basefolder, '%s-%s.png' % (self._meta.module_name, self.pk))

    def prepare_elevation_chart(self, request):
        """Converts SVG elevation URI to PNG on disk.
        """
{'fraction_non_alphanumeric': 0.10116984402079723, 'fraction_numerical': 0.009098786828422877, 'mean_word_length': 3.121875, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6163338', 'n_tokens_mistral': 2933, 'n_tokens_neox': 2739, 'n_words': 651}