src/work/alpar/graph_to_eps.cc
changeset 1050 bcc0766a7b86
parent 1047 a6094968ed09
child 1051 4ebe32765b48
equal deleted inserted replaced
1:0f6551b20442 2:9750b321bd89
       
     1 #include<math.h>
     1 #include<lemon/xy.h>
     2 #include<lemon/xy.h>
     2 #include<lemon/maps.h>
     3 #include<lemon/maps.h>
     3 #include<lemon/list_graph.h>
     4 #include<lemon/list_graph.h>
     4 
     5 
     5 ///\file
     6 
       
     7 ///\file \ingroup misc
     6 ///Simple graph drawer
     8 ///Simple graph drawer
     7 
     9 
     8 namespace lemon {
    10 namespace lemon {
     9 
    11 
    10   ///\e
    12 ///Data structure representing RGB colors.
       
    13 
       
    14 ///Data structure representing RGB colors.
       
    15 ///\ingroup misc
    11 class Color
    16 class Color
    12 {
    17 {
    13   double _r,_g,_b;
    18   double _r,_g,_b;
    14 public:
    19 public:
    15   ///\e
    20   ///Default constructor
    16   Color() {}
    21   Color() {}
    17   ///\e
    22   ///Constructor
    18   Color(double r,double g,double b) :_r(r),_g(g),_b(b) {};
    23   Color(double r,double g,double b) :_r(r),_g(g),_b(b) {};
    19   ///\e
    24   ///Returns the red component
    20   double getR() {return _r;}
    25   double getR() {return _r;}
    21   ///\e
    26   ///Returns the green component
    22   double getG() {return _g;}
    27   double getG() {return _g;}
    23   ///\e
    28   ///Returns the blue component
    24   double getB() {return _b;}
    29   double getB() {return _b;}
    25   ///\e
    30   ///Set the color components
    26   void set(double r,double g,double b) { _r=r;_g=g;_b=b; };
    31   void set(double r,double g,double b) { _r=r;_g=g;_b=b; };
    27 };
    32 };
    28   
    33   
    29   ///\e
    34 ///Default traits class of \ref GraphToEps
       
    35 
       
    36 ///Default traits class of \ref GraphToEps
       
    37 ///
       
    38 ///\c G is the type of the underlying graph.
    30 template<class G>
    39 template<class G>
    31 struct DefaultGraphToEpsTraits
    40 struct DefaultGraphToEpsTraits
    32 {
    41 {
    33   typedef G Graph;
    42   typedef G Graph;
    34   typedef typename Graph::Node Node;
    43   typedef typename Graph::Node Node;
    38   typedef typename Graph::InEdgeIt InEdgeIt;
    47   typedef typename Graph::InEdgeIt InEdgeIt;
    39   typedef typename Graph::OutEdgeIt OutEdgeIt;
    48   typedef typename Graph::OutEdgeIt OutEdgeIt;
    40   
    49   
    41 
    50 
    42   const Graph &g;
    51   const Graph &g;
    43   ConstMap<typename Graph::Node,xy<double> > coords;
    52   ConstMap<typename Graph::Node,xy<double> > _coords;
    44   ConstMap<typename Graph::Node,double > nodeSizes;
    53   ConstMap<typename Graph::Node,double > _nodeSizes;
    45 
    54 
    46   ConstMap<typename Graph::Node,Color > nodeColors;
    55   ConstMap<typename Graph::Node,Color > _nodeColors;
    47   ConstMap<typename Graph::Edge,Color > edgeColors;
    56   ConstMap<typename Graph::Edge,Color > _edgeColors;
    48   double nodeSizeScalar;
    57 
    49   double xBorder, yBorder;
    58   ConstMap<typename Graph::Edge,double > _edgeWidths;
    50     
    59   
    51   DefaultGraphToEpsTraits(G &_g) :
    60   double _edgeWidthScale;
    52     g(_g), coords(xy<double>(1,1)), nodeSizes(1.0),
    61   
    53     nodeColors(Color(1,1,1)), edgeColors(Color(0,0,0)),
    62   double _nodeScale;
    54     nodeSizeScalar(1.0), xBorder(10), yBorder(10) {}
    63   double _xBorder, _yBorder;
       
    64   double _scale;
       
    65   double _nodeBorderQuotient;
       
    66   
       
    67   bool _drawArrows;
       
    68   double _arrowLength, _arrowWidth;
       
    69   
       
    70   ///Constructor
       
    71 
       
    72   ///Constructor
       
    73   ///\param _g is a reference to the underlying graph
       
    74   DefaultGraphToEpsTraits(const G &_g) :
       
    75     g(_g), _coords(xy<double>(1,1)), _nodeSizes(1.0),
       
    76     _nodeColors(Color(1,1,1)), _edgeColors(Color(0,0,0)),
       
    77     _edgeWidths(1), _edgeWidthScale(0.3),
       
    78     _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
       
    79     _nodeBorderQuotient(.1),
       
    80     _drawArrows(false), _arrowLength(1), _arrowWidth(0.3) {}
    55 };
    81 };
    56 
    82 
    57   ///\e
    83 ///Helper class to implement the named parameters of \ref graphToEps()
       
    84 
       
    85 ///Helper class to implement the named parameters of \ref graphToEps()
       
    86 ///\todo Is 'helper class' a good name for this?
       
    87 ///
    58 template<class T> class GraphToEps : public T 
    88 template<class T> class GraphToEps : public T 
    59 {
    89 {
    60   typedef typename T::Graph Graph;
    90   typedef typename T::Graph Graph;
    61   typedef typename Graph::Node Node;
    91   typedef typename Graph::Node Node;
    62   typedef typename Graph::NodeIt NodeIt;
    92   typedef typename Graph::NodeIt NodeIt;
    68   bool dontPrint;
    98   bool dontPrint;
    69 
    99 
    70 public:
   100 public:
    71   GraphToEps(const T &t) : T(t), dontPrint(false) {};
   101   GraphToEps(const T &t) : T(t), dontPrint(false) {};
    72   
   102   
    73   template<class X> struct SetCoordsTraits : public T {
   103   template<class X> struct CoordsTraits : public T {
    74     const X &coords;
   104     const X &_coords;
    75     SetCoordsTraits(const T &t,const X &x) : T(t), coords(x) {}
   105     CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
    76   };
   106   };
    77   ///\e
   107   ///Sets the map of the node coordinates
    78   template<class X> GraphToEps<SetCoordsTraits<X> > setCoords(const X &x) {
   108 
    79     dontPrint=true;
   109   ///Sets the map of the node coordinates.
    80     return GraphToEps<SetCoordsTraits<X> >(SetCoordsTraits<X>(*this,x));
   110   ///\param x must be a node map with xy<double> or xy<int> values. 
    81   }
   111   template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
    82   template<class X> struct SetNodeSizesTraits : public T {
   112     dontPrint=true;
    83     const X &nodeSizes;
   113     return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
    84     SetNodeSizesTraits(const T &t,const X &x) : T(t), nodeSizes(x) {}
   114   }
    85   };
   115   template<class X> struct NodeSizesTraits : public T {
    86   ///\e
   116     const X &_nodeSizes;
    87   template<class X> GraphToEps<SetNodeSizesTraits<X> > setNodeSizes(const X &x)
   117     NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {}
    88   {
   118   };
    89     dontPrint=true;
   119   ///Sets the map of the node sizes
    90     return GraphToEps<SetNodeSizesTraits<X> >(SetNodeSizesTraits<X>(*this,x));
   120 
    91   }
   121   ///Sets the map of the node sizes
    92   template<class X> struct SetNodeColorsTraits : public T {
   122   ///\param x must be a node map with \c double (or convertible) values. 
    93     const X &nodeColors;
   123   template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x)
    94     SetNodeColorsTraits(const T &t,const X &x) : T(t), nodeColors(x) {}
   124   {
    95   };
   125     dontPrint=true;
    96   ///\e
   126     return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
    97   template<class X> GraphToEps<SetNodeColorsTraits<X> >
   127   }
    98   setNodeColors(const X &x)
   128    template<class X> struct EdgeWidthsTraits : public T {
    99   {
   129     const X &_edgeWidths;
   100     dontPrint=true;
   130     EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {}
   101     return GraphToEps<SetNodeColorsTraits<X> >(SetNodeColorsTraits<X>(*this,x));
   131   };
   102   }
   132   ///Sets the map of the edge widths
   103   template<class X> struct SetEdgeColorsTraits : public T {
   133 
   104     const X &edgeColors;
   134   ///Sets the map of the edge widths
   105     SetEdgeColorsTraits(const T &t,const X &x) : T(t), edgeColors(x) {}
   135   ///\param x must be a edge map with \c double (or convertible) values. 
   106   };
   136   template<class X> GraphToEps<EdgeWidthsTraits<X> > edgeWidths(const X &x)
   107   ///\e
   137   {
   108   template<class X> GraphToEps<SetEdgeColorsTraits<X> >
   138     dontPrint=true;
   109   setEdgeColors(const X &x)
   139     return GraphToEps<EdgeWidthsTraits<X> >(EdgeWidthsTraits<X>(*this,x));
   110   {
   140   }
   111     dontPrint=true;
   141 
   112     return GraphToEps<SetEdgeColorsTraits<X> >(SetEdgeColorsTraits<X>(*this,x));
   142   template<class X> struct NodeColorsTraits : public T {
   113   }
   143     const X &_nodeColors;
   114   ///\e
   144     NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {}
   115   GraphToEps<T> &scaleNodeSize(double d) {nodeSizeScalar=d;return *this;}
   145   };
       
   146   ///Sets the map of the node colors
       
   147 
       
   148   ///Sets the map of the node colors
       
   149   ///\param x must be a node map with \ref Color values. 
       
   150   template<class X> GraphToEps<NodeColorsTraits<X> >
       
   151   nodeColors(const X &x)
       
   152   {
       
   153     dontPrint=true;
       
   154     return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x));
       
   155   }
       
   156   template<class X> struct EdgeColorsTraits : public T {
       
   157     const X &_edgeColors;
       
   158     EdgeColorsTraits(const T &t,const X &x) : T(t), _edgeColors(x) {}
       
   159   };
       
   160   ///Sets the map of the edge colors
       
   161 
       
   162   ///Sets the map of the edge colors
       
   163   ///\param x must be a edge map with \ref Color values. 
       
   164   template<class X> GraphToEps<EdgeColorsTraits<X> >
       
   165   edgeColors(const X &x)
       
   166   {
       
   167     dontPrint=true;
       
   168     return GraphToEps<EdgeColorsTraits<X> >(EdgeColorsTraits<X>(*this,x));
       
   169   }
       
   170   ///Sets a global scale factor for node sizes
       
   171 
       
   172   ///Sets a global scale factor for node sizes
       
   173   ///
       
   174   GraphToEps<T> &nodeScale(double d) {_nodeScale=d;return *this;}
       
   175   ///Sets a global scale factor for edge widths
       
   176 
       
   177   ///Sets a global scale factor for edge widths
       
   178   ///
       
   179   GraphToEps<T> &edgeWidthScale(double d) {_edgeWidthScale=d;return *this;}
       
   180   ///Sets a global scale factor for the whole picture
       
   181 
       
   182   ///Sets a global scale factor for the whole picture
       
   183   ///
       
   184   GraphToEps<T> &scale(double d) {_scale=d;return *this;}
       
   185   ///Sets the width of the border around the picture
       
   186 
       
   187   ///Sets the width of the border around the picture
       
   188   ///
       
   189   GraphToEps<T> &border(double b) {_xBorder=_yBorder=b;return *this;}
       
   190   ///Sets the width of the border around the picture
       
   191 
       
   192   ///Sets the width of the border around the picture
       
   193   ///
       
   194   GraphToEps<T> &border(double x, double y) {
       
   195     _xBorder=x;_yBorder=y;return *this;
       
   196   }
       
   197   ///Sets whether to draw arrows
       
   198 
       
   199   ///Sets whether to draw arrows
       
   200   ///
       
   201   GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;}
       
   202   ///Sets the length of the arrowheads
       
   203 
       
   204   ///Sets the length of the arrowheads
       
   205   ///
       
   206   GraphToEps<T> &arrowLength(double d) {_arrowLength*=d;return *this;}
       
   207   ///Sets the width of the arrowheads
       
   208 
       
   209   ///Sets the width of the arrowheads
       
   210   ///
       
   211   GraphToEps<T> &arrowWidth(double d) {_arrowWidth*=d;return *this;}
   116   
   212   
   117   ~GraphToEps() 
   213   ~GraphToEps() 
   118   {
   214   {
   119     if(dontPrint) return;
   215     if(dontPrint) return;
   120     
   216     
   121     cout << "%!PS-Adobe-2.0 EPSF-2.0\n";
   217     cout << "%!PS-Adobe-2.0 EPSF-2.0\n";
   122     //\todo: Chech whether the graph is empty.
   218     //\todo: Chech whether the graph is empty.
   123     BoundingBox<double> bb;
   219     BoundingBox<double> bb;
   124     for(NodeIt n(g);
   220     for(NodeIt n(g);n!=INVALID;++n) {
   125 	n!=INVALID;
   221       double ns=_nodeSizes[n]*_nodeScale;
   126 	++n) {
   222       xy<double> p(ns,ns);
   127       xy<double> p(nodeSizes[n]*nodeSizeScalar,nodeSizes[n]*nodeSizeScalar);
   223       bb+=p+_coords[n];
   128       bb+=coords[n]+p;
   224       bb+=-p+_coords[n];
   129       bb+=coords[n]-p;
       
   130       }
   225       }
   131     cout << "%%BoundingBox: "
   226     cout << "%%BoundingBox: "
   132 	 << bb.left()-xBorder << ' ' << bb.bottom()-yBorder << ' '
   227 	 << bb.left()*  _scale-_xBorder << ' '
   133 	 << bb.right()+xBorder << ' ' << bb.top()+yBorder << '\n';
   228 	 << bb.bottom()*_scale-_yBorder << ' '
   134     //x1 y1 x2 y2 cr cg cb
   229 	 << bb.right()* _scale+_xBorder << ' '
   135     cout << "/l { setrgbcolor newpath moveto lineto stroke } bind def\n";
   230 	 << bb.top()*   _scale+_yBorder << '\n';
       
   231     //x1 y1 x2 y2 cr cg cb w
       
   232     cout << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n";
   136     cout << "/c { newpath dup 3 index add 2 index moveto 0 360 arc } bind def\n";
   233     cout << "/c { newpath dup 3 index add 2 index moveto 0 360 arc } bind def\n";
   137     // x y r cr cg cb
   234     // x y r cr cg cb
   138     cout << "/n { setrgbcolor 2 index 2 index 2 index c fill\n"
   235     cout << "/n { setrgbcolor 2 index 2 index 2 index c fill\n"
   139 	 << "     0 0 0 setrgbcolor dup 10 div setlinewidth c stroke\n"
   236 	 << "     0 0 0 setrgbcolor dup "
       
   237 	 << _nodeBorderQuotient << " mul setlinewidth "
       
   238 	 << 1+_nodeBorderQuotient/2 << " div c stroke\n"
   140 	 << "   } bind def\n";
   239 	 << "   } bind def\n";
   141     
   240     cout << "/arrl " << _arrowLength << " def\n";
       
   241     cout << "/arrw " << _arrowWidth << " def\n";
       
   242     // l dx_norm dy_norm
       
   243     cout << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
       
   244     //len w dx_norm dy_norm x1 y1 cr cg cb
       
   245     cout << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n"
       
   246 	 << "       /w exch def /len exch def\n"
       
   247       //	 << "       0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
       
   248 	 << "       newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
       
   249 	 << "       len w sub arrl sub dx dy lrl\n"
       
   250 	 << "       arrw dy dx neg lrl\n"
       
   251 	 << "       dx arrl w add mul dy w 2 div arrw add mul sub\n"
       
   252 	 << "       dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
       
   253 	 << "       dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
       
   254 	 << "       dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
       
   255 	 << "       arrw dy dx neg lrl\n"
       
   256 	 << "       len w sub arrl sub neg dx dy lrl\n"
       
   257 	 << "       closepath fill } bind def\n";
       
   258     cout << "\ngsave\n";
       
   259     if(_scale!=1.0) cout << _scale << " dup scale\n";
   142     cout << "%Edges:\ngsave\n";
   260     cout << "%Edges:\ngsave\n";
   143     for(NodeIt n(g);n!=INVALID;++n)
   261     for(NodeIt n(g);n!=INVALID;++n)
   144       for(OutEdgeIt e(g,n);e!=INVALID;++e)
   262       for(OutEdgeIt e(g,n);e!=INVALID;++e)
   145 	cout << coords[g.source(e)].x << ' ' << coords[g.source(e)].y << ' '
   263 	if(_drawArrows) {
   146 	     << coords[g.target(e)].x << ' ' << coords[g.target(e)].y << ' '
   264 	  xy<double> d(_coords[g.target(e)]-_coords[g.source(e)]);
   147 	     << edgeColors[e].getR() << ' '
   265 	  double l=sqrt(d.normSquare());
   148 	     << edgeColors[e].getG() << ' '
   266 	  d/=l;
   149 	     << edgeColors[e].getB() << " l\n";
   267 	  xy<double> x1(d*_nodeScale*_nodeSizes[g.source(e)]+
       
   268 			_coords[g.source(e)]);
       
   269 	  cout << l-(_nodeSizes[g.source(e)]+
       
   270 		     _nodeSizes[g.target(e)])*_nodeScale << ' '
       
   271 	       << _edgeWidths[e]*_edgeWidthScale << ' '
       
   272 	       << d.x << ' ' << d.y << ' '
       
   273 	       << x1.x << ' ' << x1.y << ' '
       
   274 	       << _edgeColors[e].getR() << ' '
       
   275 	       << _edgeColors[e].getG() << ' '
       
   276 	       << _edgeColors[e].getB() << " arr\n";
       
   277 	}
       
   278     	else cout << _coords[g.source(e)].x << ' '
       
   279 		  << _coords[g.source(e)].y << ' '
       
   280 		  << _coords[g.target(e)].x << ' '
       
   281 		  << _coords[g.target(e)].y << ' '
       
   282 		  << _edgeColors[e].getR() << ' '
       
   283 		  << _edgeColors[e].getG() << ' '
       
   284 		  << _edgeColors[e].getB() << ' '
       
   285 		  << _edgeWidths[e]*_edgeWidthScale << " l\n";
   150     cout << "grestore\n%Nodes:\ngsave\n";
   286     cout << "grestore\n%Nodes:\ngsave\n";
   151     for(NodeIt n(g);n!=INVALID;++n)
   287     for(NodeIt n(g);n!=INVALID;++n)
   152       cout << coords[n].x << ' ' << coords[n].y << ' '
   288       cout << _coords[n].x << ' ' << _coords[n].y << ' '
   153 	   << nodeSizes[n]*nodeSizeScalar << ' '
   289 	   << _nodeSizes[n]*_nodeScale << ' '
   154 	   << nodeColors[n].getR() << ' '
   290 	   << _nodeColors[n].getR() << ' '
   155 	   << nodeColors[n].getG() << ' '
   291 	   << _nodeColors[n].getG() << ' '
   156 	   << nodeColors[n].getB() << " n\n"; 
   292 	   << _nodeColors[n].getB() << " n\n"; 
   157     cout << "grestore\n";
   293     cout << "grestore\ngrestore\n";
   158   } 
   294   } 
   159 };
   295 };
   160 
   296 
   161 
   297 
       
   298 ///Generates an EPS file from a graph
       
   299 
       
   300 ///\ingroup misc
       
   301 ///Generates an EPS file from a graph.
       
   302 ///
       
   303 ///This function has a lot of \ref named-templ-param "named parameters",
       
   304 ///they are declared as the members of class \ref GraphToEps. The following
       
   305 ///example shows how to use these parameters.
       
   306 ///\code
       
   307 /// graphToEps(g).scale(10).coords(coords)
       
   308 ///              .nodeScale(2).nodeSizes(sizes)
       
   309 ///              .edgeWidthScale(.4);
       
   310 ///\endcode
       
   311 ///\sa GraphToEps
   162 template<class G>
   312 template<class G>
   163 GraphToEps<DefaultGraphToEpsTraits<G> > graphToEps(G &g)
   313 GraphToEps<DefaultGraphToEpsTraits<G> > graphToEps(G &g)
   164 {
   314 {
   165   return GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g));
   315   return GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g));
   166 }
   316 }
   192 {
   342 {
   193   ListGraph g;
   343   ListGraph g;
   194   typedef ListGraph::Node Node;
   344   typedef ListGraph::Node Node;
   195   typedef ListGraph::NodeIt NodeIt;
   345   typedef ListGraph::NodeIt NodeIt;
   196   typedef ListGraph::Edge Edge;
   346   typedef ListGraph::Edge Edge;
   197   typedef xy<double> Xy;
   347   typedef xy<int> Xy;
   198   
   348   
   199   Node n1=g.addNode();
   349   Node n1=g.addNode();
   200   Node n2=g.addNode();
   350   Node n2=g.addNode();
   201   Node n3=g.addNode();
   351   Node n3=g.addNode();
   202   Node n4=g.addNode();
   352   Node n4=g.addNode();
   204 
   354 
   205   ListGraph::NodeMap<Xy> coords(g);
   355   ListGraph::NodeMap<Xy> coords(g);
   206   ListGraph::NodeMap<double> sizes(g);
   356   ListGraph::NodeMap<double> sizes(g);
   207   ListGraph::NodeMap<int> colors(g);
   357   ListGraph::NodeMap<int> colors(g);
   208   ListGraph::EdgeMap<int> ecolors(g);
   358   ListGraph::EdgeMap<int> ecolors(g);
       
   359   ListGraph::EdgeMap<int> widths(g);
   209   
   360   
   210   coords[n1]=Xy(50,50);  sizes[n1]=1; colors[n1]=1;
   361   coords[n1]=Xy(50,50);  sizes[n1]=1; colors[n1]=1;
   211   coords[n2]=Xy(50,70);  sizes[n2]=2; colors[n2]=2;
   362   coords[n2]=Xy(50,70);  sizes[n2]=2; colors[n2]=2;
   212   coords[n3]=Xy(70,70);  sizes[n3]=1; colors[n3]=3;
   363   coords[n3]=Xy(70,70);  sizes[n3]=1; colors[n3]=3;
   213   coords[n4]=Xy(70,50);  sizes[n4]=2; colors[n4]=4;
   364   coords[n4]=Xy(70,50);  sizes[n4]=2; colors[n4]=4;
   214   coords[n5]=Xy(85,60);  sizes[n5]=3; colors[n5]=5;
   365   coords[n5]=Xy(85,60);  sizes[n5]=3; colors[n5]=5;
   215   
   366   
   216   Edge e;
   367   Edge e;
   217 
   368 
   218   e=g.addEdge(n1,n2); ecolors[e]=0;
   369   e=g.addEdge(n1,n2); ecolors[e]=0; widths[e]=1;
   219   e=g.addEdge(n2,n3); ecolors[e]=0;
   370   e=g.addEdge(n2,n3); ecolors[e]=0; widths[e]=1;
   220   e=g.addEdge(n3,n5); ecolors[e]=0;
   371   e=g.addEdge(n3,n5); ecolors[e]=0; widths[e]=3;
   221   e=g.addEdge(n5,n4); ecolors[e]=0;
   372   e=g.addEdge(n5,n4); ecolors[e]=0; widths[e]=1;
   222   e=g.addEdge(n4,n1); ecolors[e]=0;
   373   e=g.addEdge(n4,n1); ecolors[e]=0; widths[e]=1;
   223   e=g.addEdge(n2,n4); ecolors[e]=1;
   374   e=g.addEdge(n2,n4); ecolors[e]=1; widths[e]=2;
   224   e=g.addEdge(n3,n4); ecolors[e]=2;
   375   e=g.addEdge(n3,n4); ecolors[e]=2; widths[e]=1;
   225   
   376   
   226   graphToEps(g).setCoords(coords).
   377   graphToEps(g).scale(10).coords(coords).
   227     scaleNodeSize(2).setNodeSizes(sizes).
   378     nodeScale(2).nodeSizes(sizes).
   228     setNodeColors(composeMap(colorSet,colors)).
   379     nodeColors(composeMap(colorSet,colors)).
   229     setEdgeColors(composeMap(colorSet,ecolors));
   380     edgeColors(composeMap(colorSet,ecolors)).
       
   381     edgeWidthScale(.4).edgeWidths(widths).
       
   382     drawArrows().arrowWidth(1).arrowLength(1)
       
   383     ;
   230 }
   384 }