diff options
| author | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-07-04 16:11:34 +0200 | 
|---|---|---|
| committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2019-07-04 22:34:41 +0200 | 
| commit | a9b0c688f57f676f90dd27fb65520d2e1ad92f64 (patch) | |
| tree | 423c5e22b1aea6c68bbbdc6e1aaeb694fc47d039 /ishtar_common | |
| parent | eda4554eeca077f2357235414f6d59708d1b9944 (diff) | |
| download | Ishtar-a9b0c688f57f676f90dd27fb65520d2e1ad92f64.tar.bz2 Ishtar-a9b0c688f57f676f90dd27fb65520d2e1ad92f64.zip  | |
Graphs: save results, options and tests
- can generate only above and only bellow
- save dot files
- option for no color for current
- tests
Diffstat (limited to 'ishtar_common')
| -rw-r--r-- | ishtar_common/models.py | 32 | ||||
| -rw-r--r-- | ishtar_common/utils.py | 166 | 
2 files changed, 137 insertions, 61 deletions
diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 5e7f6e9b3..e8b6fc518 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -1205,6 +1205,38 @@ class RelationItem(models.Model):          _("Generated relation image (SVG)"), null=True, blank=True,          upload_to=get_image_path, help_text=max_size_help()      ) +    relation_bitmap_image = models.FileField( +        _("Generated relation image (PNG)"), null=True, blank=True, +        upload_to=get_image_path, help_text=max_size_help() +    ) +    relation_dot = models.FileField( +        _("Generated relation image (DOT)"), null=True, blank=True, +        upload_to=get_image_path, help_text=max_size_help() +    ) +    relation_image_above = models.FileField( +        _("Generated above relation image (SVG)"), null=True, blank=True, +        upload_to=get_image_path, help_text=max_size_help() +    ) +    relation_dot_above = models.FileField( +        _("Generated above relation image (DOT)"), null=True, blank=True, +        upload_to=get_image_path, help_text=max_size_help() +    ) +    relation_bitmap_image_above = models.FileField( +        _("Generated above relation image (PNG)"), null=True, blank=True, +        upload_to=get_image_path, help_text=max_size_help() +    ) +    relation_image_bellow = models.FileField( +        _("Generated bellow relation image (SVG)"), null=True, blank=True, +        upload_to=get_image_path, help_text=max_size_help() +    ) +    relation_dot_bellow = models.FileField( +        _("Generated bellow relation image (DOT)"), null=True, blank=True, +        upload_to=get_image_path, help_text=max_size_help() +    ) +    relation_bitmap_image_bellow = models.FileField( +        _("Generated bellow relation image (PNG)"), null=True, blank=True, +        upload_to=get_image_path, help_text=max_size_help() +    )      class Meta:          abstract = True diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py index 83bc56279..4f8dce853 100644 --- a/ishtar_common/utils.py +++ b/ishtar_common/utils.py @@ -17,6 +17,7 @@  # See the file COPYING for details. +from cairosvg import svg2png  from csv import QUOTE_ALL  import datetime  from functools import wraps @@ -1089,7 +1090,8 @@ def create_default_areas(models=None, verbose=False):  def get_relations_for_graph(rel_model, obj_pk, above_relations=None, -                            equal_relations=None, treated=None, styles=None): +                            equal_relations=None, treated=None, styles=None, +                            render_above=True, render_bellow=True):      """      Get all above and equal relations of an object (get all child and parent      relations) @@ -1099,6 +1101,8 @@ def get_relations_for_graph(rel_model, obj_pk, above_relations=None,      :param equal_relations: list of current equal_relations      :param treated: treated relation list to prevent circular call      :param styles: current styles +    :param render_above: render relation above the current object +    :param render_bellow: render relation bellow the current object      :return: above and equal relations list (each containing lists of two      members)      """ @@ -1114,63 +1118,81 @@ def get_relations_for_graph(rel_model, obj_pk, above_relations=None,          return above_relations, equal_relations, styles      treated.append(obj_pk) -    q = rel_model.objects.filter( -        left_record_id=obj_pk, -        relation_type__logical_relation__isnull=False -    ).values('right_record_id', 'relation_type__logical_relation') -    if not q.count(): -        return [], [] -    for relation in q.all(): -        logical_relation = relation['relation_type__logical_relation'] -        right_record = relation['right_record_id'] -        if not logical_relation: -            continue -        elif logical_relation == 'above'and \ -                (obj_pk, right_record) not in above_relations: -            above_relations.append((obj_pk, right_record)) -        elif logical_relation == 'bellow' and \ -                (right_record, obj_pk) not in above_relations: -            above_relations.append((right_record, obj_pk)) -        elif logical_relation == 'equal' and \ -                (right_record, obj_pk) not in equal_relations and \ -                (obj_pk, right_record) not in equal_relations: -            equal_relations.append((obj_pk, right_record)) -        else: -            continue -        ar, er, substyles = get_relations_for_graph( -            rel_model, right_record, above_relations, equal_relations, treated, -            styles -        ) -        styles.update(substyles) -        error_style = "color=red" -        for r in ar: -            if r not in above_relations: -                above_relations.append(r) -            reverse_rel = tuple(reversed(r)) -            if reverse_rel in above_relations: -                # circular -                if r not in styles: -                    styles[r] = [] -                if reverse_rel not in styles: -                    styles[reverse_rel] = [] - -                if error_style not in styles[r]: -                    styles[r].append(error_style) -                if error_style not in styles[reverse_rel]: -                    styles[reverse_rel].append(error_style) -            if r[0] == r[1]: -                # same entity -                if r not in styles: -                    styles[r] = [] -                if error_style not in styles[r]: -                    styles[r].append("color=red") -        for r in er: -            if r not in equal_relations: -                equal_relations.append(r) + +    for q, inverse in ( +            (rel_model.objects.filter( +                left_record_id=obj_pk, +                relation_type__logical_relation__isnull=False), False), +            (rel_model.objects.filter( +                right_record_id=obj_pk, +                relation_type__logical_relation__isnull=False), True)): +        q = q.values("left_record_id",'right_record_id', +                     'relation_type__logical_relation') +        get_above, get_bellow = render_above, render_bellow +        if inverse and (not render_above or not render_bellow): +            get_above, get_bellow = not render_above, not render_bellow + +        for relation in q.all(): +            logical_relation = relation['relation_type__logical_relation'] +            left_record = relation['left_record_id'] +            right_record = relation['right_record_id'] +            if not logical_relation: +                continue +            elif get_bellow and logical_relation == 'above' and \ +                    (left_record, right_record) not in above_relations: +                above_relations.append((left_record, right_record)) +            elif get_above and logical_relation == 'bellow' and \ +                    (right_record, left_record) not in above_relations: +                above_relations.append((right_record, left_record)) +            elif logical_relation == 'equal' and \ +                    (right_record, left_record) not in equal_relations and \ +                    (left_record, right_record) not in equal_relations: +                equal_relations.append((left_record, right_record)) +            else: +                continue + +            if right_record == obj_pk: +                other_record = left_record +            else: +                other_record = right_record + +            ar, er, substyles = get_relations_for_graph( +                rel_model, other_record, above_relations, equal_relations, +                treated, styles, render_above=render_above, +                render_bellow=render_bellow +            ) +            styles.update(substyles) +            error_style = "color=red" +            for r in ar: +                if r not in above_relations: +                    above_relations.append(r) +                reverse_rel = tuple(reversed(r)) +                if reverse_rel in above_relations: +                    # circular +                    if r not in styles: +                        styles[r] = [] +                    if reverse_rel not in styles: +                        styles[reverse_rel] = [] + +                    if error_style not in styles[r]: +                        styles[r].append(error_style) +                    if error_style not in styles[reverse_rel]: +                        styles[reverse_rel].append(error_style) +                if r[0] == r[1]: +                    # same entity +                    if r not in styles: +                        styles[r] = [] +                    if error_style not in styles[r]: +                        styles[r].append("color=red") +            for r in er: +                if r not in equal_relations: +                    equal_relations.append(r)      return above_relations, equal_relations, styles -def generate_relation_graph(obj, debug=False): +def generate_relation_graph(obj, highlight_current=True, +                            render_above=True, render_bellow=True, +                            debug=False):      if not settings.DOT_BINARY:          return @@ -1179,8 +1201,8 @@ def generate_relation_graph(obj, debug=False):      # get relations      above_relations, equal_relations, styles = get_relations_for_graph( -        rel_model, obj.pk) -    print(styles) +        rel_model, obj.pk, render_above=render_above, +        render_bellow=render_bellow)      if not above_relations and not equal_relations:          obj.relation_image = None          obj.save() @@ -1201,14 +1223,14 @@ def generate_relation_graph(obj, debug=False):                  described.append(left_pk)                  left = model.objects.get(pk=left_pk)                  style = 'label="{}"'.format(left.relation_label) -                if left.pk == obj.pk: +                if left.pk == obj.pk and highlight_current:                      style += ',style=filled,fillcolor="#C6C0C0"'                  dot_str += u'item{}[{}];\n'.format(left.pk, style)              if right_pk not in described:                  described.append(right_pk)                  right = model.objects.get(pk=right_pk)                  style = 'label="{}"'.format(right.relation_label) -                if right.pk == obj.pk: +                if right.pk == obj.pk and highlight_current:                      style += ',style=filled,fillcolor="#C6C0C0"'                  dot_str += u'item{}[{}];\n'.format(right.pk, style)              if not directed:  # on the same level @@ -1226,6 +1248,18 @@ def generate_relation_graph(obj, debug=False):      with open(dot_name, 'w') as dot_file:          dot_file.write(dot_str) +    if not render_above: +        suffix = "_above" +    elif not render_bellow: +        suffix = "_bellow" +    else: +        suffix = "" + +    with open(dot_name, "r") as dot_file: +        django_file = File(dot_file) +        attr = "relation_dot" + suffix +        getattr(obj, attr).save("relations.dot", django_file, save=True) +      # execute dot program      args = (settings.DOT_BINARY, "-Tsvg", dot_name) @@ -1234,10 +1268,20 @@ def generate_relation_graph(obj, debug=False):      with open(svg_tmp_name, "w") as svg_file:          popen = subprocess.Popen(args, stdout=svg_file)          popen.wait() -      with open(svg_tmp_name, "r") as svg_file:          django_file = File(svg_file) -        obj.relation_image.save("relations.svg", django_file, save=True) +        attr = "relation_image" + suffix +        getattr(obj, attr).save("relations.svg", django_file, save=True) + +    png_name = tempdir + os.path.sep + "relations.png" + +    with open(png_name, "wb") as png_file: +        svg2png(open(svg_tmp_name, 'rb').read(), +                write_to=png_file) +    with open(png_name, "rb") as png_file: +        django_file = File(png_file) +        attr = "relation_bitmap_image" + suffix +        getattr(obj, attr).save("relations.png", django_file, save=True)      if debug:          print(u"DOT file: {}. Tmp SVG file: {}.".format(dot_name, svg_tmp_name))  | 
