1 // ==========================================================================
2 // SeqAn - The Library for Sequence Analysis
3 // ==========================================================================
4 // Copyright (c) 2006-2010, Knut Reinert, FU Berlin
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 // * Neither the name of Knut Reinert or the FU Berlin nor the names of
16 // its contributors may be used to endorse or promote products derived
17 // from this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
23 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29 // DAMAGE.
30 //
31 // ==========================================================================
32
33 #ifndef SEQAN_HEADER_MISC_SVG_H
34 #define SEQAN_HEADER_MISC_SVG_H
35
36 namespace SEQAN_NAMESPACE_MAIN
37 {
38
39 //////////////////////////////////////////////////////////////////////////////
40 // SVG File Context
41 //////////////////////////////////////////////////////////////////////////////
42
43 struct SVGFile
44 {
45 std::fstream file;
46
47 Pair<int> cursor;
48 String<CharString> style;
49
50 int dpSequence;
51 int dpMatrix;
52 int dpTrace;
53
54 int text;
55
56 int readForward;
57 int readReverse;
58 int readText;
59 int rulerTextTicks;
60 int rulerTextLabel;
61
62 friend inline void svgWriteHeader(SVGFile &svg);
63 friend inline void svgWriteFooter(SVGFile &svg);
64
65 template <typename TFileName>
66 friend inline bool open(SVGFile &svg, TFileName const &fileName);
67 friend inline bool close(SVGFile &svg);
68
SVGFileSVGFile69 SVGFile():
70 cursor(0,0)
71 {
72 resetStyles();
73 }
74
SVGFileSVGFile75 SVGFile(char const *fileName):
76 cursor(0,0)
77 {
78 resetStyles();
79 open(*this, fileName);
80 }
81
~SVGFileSVGFile82 ~SVGFile()
83 {
84 close(*this);
85 }
86
87 private:
88
resetStylesSVGFile89 inline void resetStyles()
90 {
91 clear(style);
92 readText = dpSequence = length(style);
93 appendValue(style, "style=\"text-anchor:middle; font-family:Bitstream Vera Sans,Verdana,sans-serif;\" font-size=\"18px\"");
94 text = length(style);
95 appendValue(style, "style=\"text-anchor:middle; font-family:Courier New,Verdana,sans-serif; font-weight:bold;\" font-size=\"20px\"");
96 rulerTextTicks = length(style);
97 appendValue(style, "style=\"text-anchor:middle; font-family:Verdana,sans-serif;\" font-size=\"6px\"");
98 rulerTextLabel = length(style);
99 appendValue(style, "style=\"text-anchor:left; font-family:Verdana,sans-serif; font-weight:bold;\" font-size=\"8px\"");
100
101 dpMatrix = length(style);
102 appendValue(style, "style=\"stroke:lightgray;stroke-width:1;\" marker-end=\"url(#startMarkerNormal)\"");
103 dpTrace = length(style);
104 appendValue(style, "style=\"stroke:black;stroke-width:2;\" marker-end=\"url(#startMarkerBold)\"");
105
106 readForward = length(style);
107 appendValue(style, "style=\"stroke:darkblue;stroke-width:3;\"");
108 appendValue(style, "style=\"stroke:lightblue;stroke-width:1;\"");
109 appendValue(style, "style=\"stroke:darkblue;stroke-width:3;\" marker-end=\"url(#startMarkerForward)\"");
110 appendValue(style, "style=\"stroke:lightblue;stroke-width:1;\" marker-end=\"url(#startMarkerForward)\"");
111 readReverse = length(style);
112 appendValue(style, "style=\"stroke:darkred;stroke-width:3;\"");
113 appendValue(style, "style=\"stroke:salmon;stroke-width:1;\"");
114 appendValue(style, "style=\"stroke:darkred;stroke-width:3;\" marker-end=\"url(#startMarkerReverse)\"");
115 appendValue(style, "style=\"stroke:salmon;stroke-width:1;\" marker-end=\"url(#startMarkerReverse)\"");
116 }
117 };
118
svgWriteHeader(SVGFile & svg)119 inline void svgWriteHeader(SVGFile &svg)
120 {
121 svg.file << "<?xml version=\"1.0\"?>" << std::endl;
122 svg.file << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"" << std::endl;
123 svg.file << " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" << std::endl;
124 svg.file << std::endl;
125 svg.file << "<svg version=\"1.1\"" << std::endl;
126 svg.file << " xmlns=\"http://www.w3.org/2000/svg\"" << std::endl;
127 svg.file << " xmlns:xlink=\"http://www.w3.org/1999/xlink\">" << std::endl;
128 svg.file << "<defs>" << std::endl;
129
130 // trace back arrow markers
131 svg.file << " <g id=\"arrowMarker\" stroke-linecap=\"round\">" << std::endl;
132 svg.file << " <line x1=\"-6\" y1=\"1.5\" x2=\"0\" y2=\"0\" />" << std::endl;
133 svg.file << " <line x1=\"-6\" y1=\"-1.5\" x2=\"0\" y2=\"0\" />" << std::endl;
134 svg.file << " </g>" << std::endl;
135 svg.file << " <marker id=\"startMarkerNormal\" markerWidth=\"6\" markerHeight=\"3\" style=\"overflow:visible\" orient=\"auto\" markerUnits=\"userSpaceOnUse\">" << std::endl;
136 svg.file << " <use xlink:href=\"#arrowMarker\" stroke=\"lightgray\" />" << std::endl;
137 svg.file << " </marker>" << std::endl;
138 svg.file << " <marker id=\"startMarkerBold\" markerWidth=\"6\" markerHeight=\"4\" style=\"overflow:visible\" orient=\"auto\" markerUnits=\"userSpaceOnUse\">" << std::endl;
139 svg.file << " <use xlink:href=\"#arrowMarker\" stroke-width=\"2\" stroke=\"black\" />" << std::endl;
140 svg.file << " </marker>" << std::endl;
141
142 // read mapping arrow markers
143 svg.file << " <marker id=\"startMarkerForward\" markerWidth=\"10\" markerHeight=\"4\" style=\"overflow:visible\" orient=\"auto\" markerUnits=\"userSpaceOnUse\">" << std::endl;
144 svg.file << " <polyline points=\"-8,0 -9,-6 3,0 -9,6 -8,0\" fill=\"darkblue\" />" << std::endl;
145 svg.file << " </marker>" << std::endl;
146 svg.file << " <marker id=\"startMarkerReverse\" markerWidth=\"10\" markerHeight=\"4\" style=\"overflow:visible\" orient=\"auto\" markerUnits=\"userSpaceOnUse\">" << std::endl;
147 svg.file << " <polyline points=\"-8,0 -9,-6 3,0 -9,6 -8,0\" fill=\"darkred\" />" << std::endl;
148 svg.file << " </marker>" << std::endl;
149
150 svg.file << " </defs>" << std::endl;
151 svg.file << std::endl;
152 }
153
svgWriteFooter(SVGFile & svg)154 inline void svgWriteFooter(SVGFile &svg)
155 {
156 svg.file << std::endl;
157 svg.file << "</svg>" << std::endl;
158 }
159
160
161 template <typename TFileName>
open(SVGFile & svg,TFileName const & fileName)162 inline bool open(SVGFile &svg, TFileName const &fileName)
163 {
164 svg.file.open(fileName, std::ios_base::out);
165 if (!svg.file.is_open()) return false;
166 svgWriteHeader(svg);
167 return true;
168 }
169
close(SVGFile & svg)170 inline bool close(SVGFile &svg)
171 {
172 if (svg.file.is_open())
173 {
174 svgWriteFooter(svg);
175 svg.file.close();
176 }
177 return true;
178 }
179
180 template <typename TChar>
181 inline void
_streamPut(SVGFile & svg,TChar character)182 _streamPut(SVGFile & svg, TChar character)
183 {
184 if (convert<char>(character) == '\n')
185 {
186 ++svg.cursor.i2;
187 svg.cursor.i1 = 0;
188 } else if (convert<char>(character) == '\t')
189 {
190 svg.cursor.i1 = (svg.cursor.i1 & ~7) + 8;
191 } else
192 {
193 if (convert<char>(character) != ' ')
194 {
195 svg.file << "<g transform=\"translate(" << svg.cursor.i1*20+10 << ',' << svg.cursor.i2*20+10 << ")\"><text y=\"0.3em\" " << svg.style[svg.text] << '>';
196 _streamPut(svg.file, convert<char>(character));
197 svg.file << "</text></g>" << std::endl;
198 }
199 ++svg.cursor.i1;
200 }
201 }
202
203 template <typename TFormatTag, typename TContigGaps, typename TContigName>
_printContig(SVGFile & svg,Tag<TFormatTag> const & format,AlignedReadLayout &,TContigGaps & contigGaps,TContigName const & contigName)204 inline void _printContig(
205 SVGFile &svg,
206 Tag<TFormatTag> const &format,
207 AlignedReadLayout &,
208 TContigGaps &contigGaps,
209 TContigName const &contigName)
210 {
211 typedef typename Iterator<TContigGaps, Standard>::Type TContigIterator;
212
213 TContigIterator cit = begin(contigGaps, Standard());
214 TContigIterator citEnd = end(contigGaps, Standard());
215 for (__int64 ofs = 0; cit != citEnd; ++cit, ++ofs)
216 {
217 if (!isGap(cit))
218 {
219 if (ofs == 0)
220 {
221 svg.file << "<g transform=\"translate(" << ofs*20+2 << ',' << svg.cursor.i2*20+10 << ")\"><text y=\"0.3em\" " << svg.style[svg.rulerTextLabel] << '>';
222 svg.file << contigName << "</text></g>" << std::endl;
223 }
224
225 __int64 seqPos = cit.current.seqPos + 1;
226 if (seqPos % 5 == 0)
227 {
228 if (seqPos % 10 == 0)
229 {
230 if (ofs >= 5)
231 {
232 svg.file << "<g transform=\"translate(" << ofs*20+10 << ',' << svg.cursor.i2*20+10 << ")\"><text y=\"0.3em\" " << svg.style[svg.rulerTextTicks] << '>';
233 svg.file << seqPos << "</text></g>" << std::endl;
234 }
235
236 svg.file << "<line x1=\"" << ofs*20+10 << "\" x2=\"" << ofs*20+10 << "\" ";
237 svg.file << "y1=\"" << svg.cursor.i2*20+12 << "\" y2=\"" << svg.cursor.i2*20+15 << "\" ";
238 } else {
239 svg.file << "<line x1=\"" << ofs*20+10 << "\" x2=\"" << ofs*20+10 << "\" ";
240 svg.file << "y1=\"" << svg.cursor.i2*20+12 << "\" y2=\"" << svg.cursor.i2*20+15 << "\" ";
241 }
242 svg.file << "stroke-width=\"1\" stroke=\"gray\" />" << std::endl;
243 }
244 }
245 }
246 _streamPut(svg, '\n');
247
248 int savedStyle = svg.text;
249 svg.text = svg.readText;
250 write(svg, contigGaps, "", format);
251 svg.text = savedStyle;
252 }
253
254 template <typename TFormatTag, typename TContigGaps, typename TReadGaps, typename TAlignedRead, typename TLine>
_printRead(SVGFile & svg,Tag<TFormatTag> const &,AlignedReadLayout & layout,TContigGaps & contigGaps,TReadGaps & readGaps,TAlignedRead & alignedRead,TLine line)255 inline void _printRead(
256 SVGFile &svg,
257 Tag<TFormatTag> const &,
258 AlignedReadLayout &layout,
259 TContigGaps &contigGaps,
260 TReadGaps &readGaps,
261 TAlignedRead &alignedRead,
262 TLine line)
263 {
264 typedef typename Iterator<TContigGaps, Standard>::Type TContigIterator;
265 typedef typename Iterator<TReadGaps, Standard>::Type TIterator;
266
267 __int64 x;
268 __int64 xEnd;
269 int style, arrow;
270 const char *first;
271 const char *second;
272 if (alignedRead.beginPos < alignedRead.endPos)
273 {
274 xEnd = alignedRead.beginPos * 20;
275 x = xEnd + 5;
276 first = "<line x1=\"";
277 second = "\" x2=\"";
278 style = svg.readForward;
279 arrow = 0;
280 } else {
281 xEnd = alignedRead.endPos * 20;
282 x = xEnd + 10;
283 first = "<line x2=\"";
284 second = "\" x1=\"";
285 style = svg.readReverse;
286 arrow = 2;
287 }
288 line = svg.cursor.i2 * 20 + 10;
289
290 if (length(layout.mateCoords) <= alignedRead.pairMatchId)
291 resize(layout.mateCoords, alignedRead.pairMatchId + 1, Pair<int>(-1,-1));
292 else
293 {
294 if (layout.mateCoords[alignedRead.pairMatchId].i2 != -1)
295 {
296 Pair<__int64> a(alignedRead.beginPos * 20, line);
297 Pair<__int64> b(layout.mateCoords[alignedRead.pairMatchId]);
298 if (a.i1 < b.i1)
299 {
300 Pair<__int64> tmp = a;
301 a = b;
302 b = tmp;
303 }
304 __int64 dx = (b.i1 - a.i1);
305 __int64 dy = (b.i2 - a.i2);
306
307 svg.file << "<path d=\"M " << a.i1 << ',' << a.i2;
308 svg.file << " C " << a.i1+dy/10 << ',' << a.i2-dx/10;
309 svg.file << ' ' << b.i1+dy/10 << ',' << b.i2-dx/10;
310 svg.file << ' ' << b.i1 << ',' << b.i2;
311 svg.file << "\" stroke-width=\"2\" stroke=\"black\" stroke-opacity=\"0.2\" fill=\"none\"/>";
312 }
313 else
314 layout.mateCoords[alignedRead.pairMatchId] = Pair<int>(alignedRead.beginPos * 20, line);
315 }
316
317
318 TContigIterator cit = begin(contigGaps, Standard()) + _min(alignedRead.beginPos, alignedRead.endPos);
319 TIterator it = begin(readGaps, Standard());
320 TIterator itEnd = end(readGaps, Standard());
321 int lastWasGap = -1;
322 int inGap;
323
324 for (; it != itEnd; ++it, ++cit, xEnd += 20)
325 {
326 inGap = isGap(it);
327 if (lastWasGap != inGap || inGap != static_cast<int>(isGap(cit)) || (!inGap && convert<Dna5>(*cit) != convert<Dna5>(*it)))
328 {
329 if (x < xEnd && lastWasGap != -1)
330 {
331 svg.file << first << x << "\" y1=\"" << line << second << xEnd;
332 svg.file << "\" y2=\"" << line << "\" " << svg.style[style + arrow + lastWasGap] << " />" << std::endl;
333 arrow = 0;
334 }
335 lastWasGap = inGap;
336 x = xEnd;
337 if (!inGap && convert<Dna5>(*cit) != convert<Dna5>(*it))
338 {
339 svg.file << "<g transform=\"translate(" << xEnd + 10 << ',' << line << ")\"><text y=\"0.3em\" " << svg.style[svg.readText] << '>';
340 _streamPut(svg.file, convert<char>(*it));
341 svg.file << "</text></g>" << std::endl;
342 x += 20;
343 arrow = 0;
344 }
345 }
346 }
347 if (x < xEnd && lastWasGap != -1)
348 {
349 if (alignedRead.beginPos < alignedRead.endPos)
350 {
351 arrow = 2;
352 xEnd -= 10;
353 } else
354 xEnd -= 5;
355 svg.file << first << x << "\" y1=\"" << line << second << xEnd;
356 svg.file << "\" y2=\"" << line << "\" " << svg.style[style + arrow + lastWasGap] << " />" << std::endl;
357 }
358 }
359
360
361 //////////////////////////////////////////////////////////////////////////////
362 // stream operators
363 //////////////////////////////////////////////////////////////////////////////
364 /*
365 template <typename TSource>
366 inline SVGFile &
367 operator << (SVGFile & target,
368 TSource source)
369 {
370 SEQAN_CHECKPOINT
371 write(target, source);
372 return target;
373 }
374 */
375
376 inline SVGFile &
377 operator << (SVGFile & target, char source)
378 {
379 SEQAN_CHECKPOINT
380 write(target, source);
381 return target;
382 }
383
384 inline SVGFile &
385 operator << (SVGFile & target, char const *source)
386 {
387 SEQAN_CHECKPOINT
388 write(target, source);
389 return target;
390 }
391
392
393 template <typename TStringSet, typename TTrace, typename TIndexPair>
394 void
_alignNeedlemanWunschMatrix(SVGFile & svg,TStringSet const & str,TTrace const & trace,TIndexPair const &)395 _alignNeedlemanWunschMatrix(SVGFile& svg,
396 TStringSet const& str,
397 TTrace const& trace,
398 TIndexPair const&)
399 {
400 SEQAN_CHECKPOINT
401 typedef typename Size<TStringSet>::Type TSize;
402 typedef typename Value<TTrace>::Type TTraceValue;
403
404 // TraceBack values
405 const int Diagonal = 0;
406 const int Horizontal = 1;
407 const int Vertical = 2;
408
409 // Initialization
410 TSize numCols = length(str[0]);
411 TSize numRows = length(str[1]);
412
413 // Print trace matrix
414 for (TSize pos0 = 0; pos0 < numCols; ++pos0)
415 {
416 for (TSize pos1 = 0; pos1 < numRows; ++pos1)
417 {
418 int tv =(int)trace[pos0*numRows + pos1];
419 if (tv & (1 << Diagonal))
420 svg.file << "<line x2=\"" << pos0*20+10 << "\" y2=\"" << pos1*20+10 << "\"" << " x1=\"" << (pos0+1)*20+10 << "\" y1=\"" << (pos1+1)*20+10 << "\" " << svg.style[svg.dpMatrix] << " />" << std::endl;
421
422 if (tv & (1 << Horizontal))
423 svg.file << "<line x2=\"" << pos0*20+10 << "\" y2=\"" << (pos1+1)*20+10 << "\"" << " x1=\"" << (pos0+1)*20+10 << "\" y1=\"" << (pos1+1)*20+10 << "\" " << svg.style[svg.dpMatrix] << " />" << std::endl;
424
425 if (tv & (1 << Vertical))
426 svg.file << "<line x2=\"" << (pos0+1)*20+10 << "\" y2=\"" << pos1*20+10 << "\"" << " x1=\"" << (pos0+1)*20+10 << "\" y1=\"" << (pos1+1)*20+10 << "\" " << svg.style[svg.dpMatrix] << " />" << std::endl;
427 }
428 }
429
430 // Print sequences
431 for (TSize pos0 = 0; pos0 < numCols; ++pos0)
432 svg.file << "<g transform=\"translate(" << pos0*20+20 << ",5)\"><text y=\"0.3em\" " << svg.style[svg.dpSequence] << '>' << str[0][pos0] << "</text></g>" << std::endl;
433
434 for (TSize pos1 = 0; pos1 < numRows; ++pos1)
435 svg.file << "<g transform=\"translate(0," << pos1*20+25 << ")\"><text y=\"0.3em\" " << svg.style[svg.dpSequence] << '>' << str[1][pos1] << "</text></g>" << std::endl;
436 }
437
438 template <typename TStringSet, typename TId, typename TPos, typename TTraceValue>
439 inline void
_alignTracePrint(SVGFile & svg,TStringSet const &,TId const,TPos pos1,TId const,TPos pos2,TPos const segLen,TTraceValue const tv)440 _alignTracePrint(SVGFile& svg,
441 TStringSet const&,
442 TId const,
443 TPos pos1,
444 TId const,
445 TPos pos2,
446 TPos const segLen,
447 TTraceValue const tv)
448 {
449 // TraceBack values
450 TTraceValue Diagonal = 0; TTraceValue Horizontal = 1; TTraceValue Vertical = 2;
451
452 svg.file << "<line x2=\"" << pos1*20+10 << "\" y2=\"" << pos2*20+10 << "\"";
453 if (tv == Diagonal) {
454 pos1 += segLen; pos2 += segLen;
455 } else if (tv == Horizontal) {
456 pos1 += segLen;
457 } else if (tv == Vertical) {
458 pos2 += segLen;
459 }
460 svg.file << " x1=\"" << pos1*20+10 << "\" y1=\"" << pos2*20+10;
461 svg.file << "\" " << svg.style[svg.dpTrace] << " />" << std::endl;
462 }
463
464 //////////////////////////////////////////////////////////////////////////////
465
466
467
468 } //namespace SEQAN_NAMESPACE_MAIN
469
470 #endif //#ifndef SEQAN_HEADER_...
471