2015-09-05 14 views
8

Jestem studentem pierwszego roku medycyny i chciałbym użyć Graphviz do stworzenia łatwego do zinterpretowania wykresu struktur anatomicznych człowieka i ich powiązań funkcjonalnych. W szczególności chciałbym stworzyć wykres z około 50 mięśniami, 50 nerwami, 50 tętnicami, 80 kościami i procesami kostnymi, bliższymi i dalszymi punktami przywiązania mięśni do procesów kostnych, które to nerwy unerwiają mięśnie, które tętnice perfundują jakie mięśnie, et. glin.Graphviz dla ludzkich struktur anatomicznych i ich związków funkcjonalnych

Dla pełnego obrazu przedstawiającego wszystkie te struktury i wszystkie ich relacje (które będą bardzo skomplikowane, wiem) Myślę, że wykres jest prawdopodobnie najlepszym sposobem reprezentowania tych struktur i ich zależności funkcjonalnych, a Graphviz wydaje się być dobre oprogramowanie do tworzenia takich wykresów, ale istnieją różne rodzaje krawędzi, które łączą struktury. Na przykład, opierając się wyłącznie na makroskopowej obserwacji grubych struktur, wydaje się, że nerw pachowy pochodzi z tylnego sznurka splotu ramiennego (BP), który zawiera włókna z górnych, środkowych i dolnych pni BP, a te trzy pnie zawierają włókna nerwowe z każdego przedniego rami pochodzącego z nerwów rdzeniowych C5, C6, C7, C8 i T1. Jednakże, pomimo wyglądu fizycznego, łączność elektryczna nerwu pachowego jest taka, że ​​w rzeczywistości zawiera on włókna nerwowe pochodzące z przedniej ściany tylko nerwów rdzeniowych C5 i C6 (patrz zdjęcie i powinienem tutaj wyjaśnić, że wszystkie włókna nerwowe ze wszystkich nerwów rdzeniowych są ten sam kolor w rzeczywistej anatomii brutto, więc spróbuj wyobrazić sobie obraz bez kolorów, aby uzyskać pojęcie o fizycznych połączeniach w porównaniu do połączeń elektrycznych, jak pokazano w kolorach). Aby uzyskać dokładną reprezentację fizycznej łączności i łączności elektrycznej dla nerwu pachowego i wszystkich włókien nerwu górnego, z których on pochodzi, potrzebuję co najmniej dwóch różnych rodzajów krawędzi: "fizycznych" krawędzi i "elektrycznych" krawędzi . Myślę, że Graphviz może robić takie rzeczy, ale jestem nowy w korzystaniu z Graphviz i nie mam pewności co do najlepszego sposobu, aby to osiągnąć (chociaż nie jest to moje główne pytanie tutaj).

Human brachial plexus

Ja też trzeba znaleźć drogę do reprezentowania relacji, takich jak te opisane powyżej, przy czym włókna nerwowe przechodzą przez wiele struktur na ich drodze do nazwanych nerwów końcowych z tych struktur. Na przykład, na powyższym obrazku, kolor jest używany do pokazania jednego ciągłego zestawu włókien nerwowych pochodzących z C6 (niebieski) i kręcenia ich do wszystkich następujących struktur: "Nerw do subklawu", "Pnia górna", "Przewód boczny" "," Mediana nerwu "," Boczny nerw grzbietowy "," nerw osiowy "i" nerw radialny ".

Próbowałem reprezentować niektóre z tego z Graphviz, jak na poniższym obrazie.

Graphviz representation of some parts of human brachial plexus

że stworzyłem z linii DOT kodu języka jak poniżej (jest niekompletny fragment kodu, a nie cały plik DOT użyłem do stworzenia tego obrazu):

snc05 -- bput -- bplc -- mn[color="#ffde17",penwidth=3]; 
snc06 -- bput -- bplc -- mn[color="#0056e0",penwidth=3]; 
snc07 -- bpmt -- bplc -- mn[color="#ff6f00",penwidth=3]; 
snc08 -- bplt -- bpmc -- mn[color="#be1e2d",penwidth=3]; 
snt01 -- bplt -- bpmc -- mn[color="#00a651",penwidth=3]; 

snc05 -- bput -- bppc -- rn[color="#ffde17",penwidth=3]; 
snc06 -- bput -- bppc -- rn[color="#0056e0",penwidth=3]; 
snc07 -- bpmt -- bppc -- rn[color="#ff6f00",penwidth=3]; 
snc08 -- bplt -- bppc -- rn[color="#be1e2d",penwidth=3]; 
snt01 -- bplt -- bppc -- rn[color="#00a651",penwidth=3]; 

Ale główny problem z tym odwzorowaniem polega na tym, że istnieje wiele niebieskich krawędzi między C6 a górnym tułowia splotu ramiennego i istnieje wiele żółtych krawędzi pomiędzy C5 a górnym tułowia splotu ramiennego i istnieje wiele pomarańczowych krawędzi między C7 a środkowym tułowia splotu ramiennego i pomiędzy biustonoszem znajduje się wiele pomarańczowych krawędzi środkowy splot środkowy i splot boczny splotu ramiennego.

Wiem, dlaczego istnieje wiele krawędzi tego samego koloru, co w powyższym akapicie. Tworzyłem je jawnie w pliku DOT. A jeśli logika jest poprawna (mogę ostatecznie sparsować ten plik DOT za pomocą pythona lub czegoś podobnego), faktycznie chcę, aby plik DOT zawierał te same krawędzie tego samego koloru. Ale nie chcę, aby wiele krawędzi tego samego koloru w renderowanym obrazie.

Moje główne pytanie brzmi: w jaki sposób mogę przekonwertować Graphviz na pomijanie renderowania 5 niebieskich krawędzi między C6 a górnym (górnym) pniem i renderować je jako tylko 1 niebieską krawędź? Kolejnym pytaniem jest: jak zmusić Graphviz do renderowania krawędzi o różnych kolorach w taki sposób, aby nie nakładały się na siebie, aby każda różnobarwna krawędź pozostała wyraźna w całym zakresie (od początkowego węzła do sąsiedniego). węzeł)? Najlepszym przykładem tego problemu na powyższym obrazku są dwie krawędzie (niebieska i żółta) łączące górny (górny) tułów z bocznym sznurem. Chociaż niebieskie i żółte krawędzie są wyraźne w pobliżu dwóch węzłów, w środku ich rozpiętości, zachodzą na siebie tak całkowicie, że trudno jest zauważyć, że są tam dwie krawędzie; niebieski niemal całkowicie zasłania żółty. Chciałbym znaleźć ogólny sposób, by zmusić Graphviz do tego, aby niebieskie i żółte krawędzie nie nakładały się na siebie (nie chciałbym, aby wizualnie sprawdzałem obraz i korygowałem plik DOT, ale raczej znajdowałem jakiś sposób mówiąc, że Graphviz nie pozwala, aby krawędzie w ogóle się pokrywały, chyba że są tego samego koloru).

Poprzednie zdjęcie Graphviz zaczyna pokazywać, dlaczego to pytanie jest dla mnie ważne, ale teraz pracując nad tym dłużej, poniższy obraz pokazuje to jeszcze lepiej. Rzeczy stają się tak niechlujne, że interpretacja staje się trudna.

Nerves of the upper extremity according to Moore 2ed COA

@Simon dzięki za wyjaśnienie (w komentarzu poniżej) o GNU head. head na OS X zachowuje się inaczej, więc użyłem twojego skryptu sed, który usunął mój pierwszy problem. Jednak myślę, że twój skrypt removeDupEdge może powodować inne problemy z moim plikiem .gv.

Aby zademonstrować, zacznę od Twojego przykładu multiEdge.gv pliku. Wprowadzenie pewnych niewielkich zmian, mam:

graph { 
    node [style=filled]; 
    a [label="a1",fillcolor=green] 
    b [label="b1",fillcolor=purple] 
    c [label="c1"] 
    d [label="d1"] 
    e [label="e1"] 

    a -- b -- c[color = blue]; 
    a -- b -- c -- d[color = red]; 
    a -- c; 
    a -- b -- c -- d -- e[color = blue]; 
} 

Twój removeDupEdge scenariusz wydaje się obsługiwać dwie linie powyżej cechach źle:

$ ./removeDupEdge <multiEdge.gv 
graph { 
    node [label="\N", 
     label=a1]; 
     label=b1]; 
     style=filled 
    ]; 
    a [fillcolor=green, 
    a -- b [color=blue]; 
    a -- b [color=red]; 
    a -- c; 
    b [fillcolor=purple, 
    b -- c [color=blue]; 
    b -- c [color=red]; 
    c [label=c1]; 
    c -- d [color=blue]; 
    c -- d [color=red]; 
    d [label=d1]; 
    d -- e [color=blue]; 
    e [label=e1]; 
} 

I myślę, że to nie jest już prawidłowy kod języka DOT. Wasz skrypt removeDupEdge wygląda bardzo obiecująco, ale nie jestem pewien, jak to naprawić w przykładzie, który pokazałem powyżej. Mój plik .gv ma więcej niż 700 linii, a także używam komentarzy w stylu C++ dozwolonych w DOT language documentation. Nie jestem pewien, czy komentarze mogą powodować problemy w twoim skrypcie removeDupEdge.

+0

Może ten facet ma odpowiedź: http://www.logarithmic.net/pfh/ghost-diagrams (programistycznie robi imponujące diagramy) –

+0

Te diagramy duchów nie są wizualizacjami danych, ale systemami l https: // en .wikipedia.org/wiki/L-system – widged

+0

Może układ radialny będzie działał lepiej - http://www.graphviz.org/content/twopi2 – widged

Odpowiedz

2

(Silnie stworzony, aby proces był trwały, aby węzły wiele atrybutów i na krawędziach)

w odniesieniu do pierwszego pytanie GraphViz, grouping the same edges pokazuje, że użycie słowa kluczowego strict zatrzymuje graphviz wyświetlanie wielu krawędzi między węzłami. Jednak to nie pozwala wyświetlić jednej krawędzi dla każdego koloru między dwoma węzłami. Najlepszym sposobem na zrobienie tego, o ile widzę, byłoby przetworzyć plik graphviz, a następnie go wyświetlić.

Na przykład, biorąc pod uwagę multiEdge.gv:

graph { 
    node [style=filled]; 
    a [label="a1",fillcolor=green] 
    b [label="b1",fillcolor=purple] 
    c [label="c1"] 
    d [label="d1"] 
    e [label="e1"] 

    a -- b -- c[color = blue]; 
    a -- b -- c -- d[color = red]; 
    a -- c; 
    a -- b -- c -- d -- e[color = blue]; 
} 

... która wygląda następująco:

enter image description here

...możemy przetworzyć go z poniższej removeDupEdge skryptu:

#!/bin/sh 
neato -Tcanon | perl -p -e 's/,\n/,/' >tmp.tmp 
head -3 tmp.tmp >header.tmp 
tail -1 tmp.tmp >tail.tmp 
tail -n +4 tmp.tmp | sed -n '$ !p' | sort | uniq | cat header.tmp - tail.tmp 

... który najpierw wytwarza wersję skryptu w formie kanonicznej, w którym każda krawędź przechodzi tylko pomiędzy dwoma węzłami. Niestety, forma kanoniczna umieszcza również listę atrybutów węzłów i atrybutów elementów na wielu liniach kończących się przecinkami, aby następna część skryptu używała perl do ponownego łączenia wszystkich linii kończących się przecinkami (dzięki odpowiedzi na How can you combine all lines that end with a backslash character?). Następnie skrypt zapisuje trzy górne wiersze i dolną linię formy kanonicznej odpowiednio jako nagłówek i stopkę, przed wykonaniem wszystkich linii nagłówka i stopki, sortując je, zachowując tylko unikalne linie, a następnie łącząc nagłówek i stopkę z powrotem do utworzyć legalny plik xdot. Wynik jest następujący:

$ removeDupEdge <multiEdge.gv 
graph { 
     node [label="\N",    style=filled 
     ]; 
     a -- b [color=blue]; 
     a -- b [color=red]; 
     a -- c; 
     a  [fillcolor=green,    label=a1]; 
     b -- c [color=blue]; 
     b -- c [color=red]; 
     b  [fillcolor=purple,    label=b1]; 
     c -- d [color=blue]; 
     c -- d [color=red]; 
     c  [label=c1]; 
     d -- e [color=blue]; 
     d  [label=d1]; 
     e  [label=e1]; 
} 

Możemy następnie wyświetlić go z:

$ removeDupEdge <multiEdge.gv | neato -Tpng -omultiEdge.png 

... dostać:

enter image description here

... który pokazuje tylko jedną kopię z każdej identycznej krawędzi.

Scenariusz może być nieco bardziej odporne wkładając sed 's/ */ /g' przed sort, ponieważ mogłoby usunąć bez istotnych miejsc z pliku xdot przed sortowaniem i porównanie linii. Jednak usunie również wiele spacji z (powiedzmy) etykiet węzłów, co może nie być pożądane.

Jeśli chodzi o komentarze w oryginalnym źródle xdot, nie spowoduje to problemu, ponieważ zostaną usunięte w procesie kanonizacji.

+2

To jest rozwiązanie, na które poszłam. Z wyjątkiem być może napisałbym to w Perlu lub tcl (lub nawet javascript). Możesz nawet zgrupować linie grubsze, aby zaznaczyć, że są zgrupowane (np. Autobusy w schemacie elektroniki) – slebetman

+1

Napisane w Perlu, Tcl lub Pythonie (co byłoby moim upodobaniem), byłoby całkiem proste zmodyfikowanie atrybutów zduplikowanych krawędzi do spraw, by były grubsze. Na przykład moja odpowiedź na [Jaki jest najlepszy sposób narysowania dużego wykresu za pomocą graphvis] (http://stackoverflow.com/questions/16173764/what-is-the-best-way-to-draw-large-graph- using-graphvis/16311864 # 16311864) modyfikuje ważenie krawędzi za pomocą skryptu w języku Python. – Simon

+0

Dziękuję bardzo za odpowiedź. To brzmi jak byłoby to dobre rozwiązanie dla mnie, ale gdy próbuję, pojawia się błąd z uruchomieniem twojego skryptu removeDupEdge: "head: nielegalna liczba linii - -1".Myślałem, że "head -n -1" musiał być winowajcą, ale kiedy zmienię tę część kodu, aby odczytać jako "head -n 1" (usunięcie kreski), moje wyniki z uruchamiania skryptu na twoim multiEdge.gv różni się od wyświetlanego wyniku. – Osteoboon

Powiązane problemy