Answers.Body: <p>Probably it is better to use dedicated tools, however, here is a quick R workaround. It is relatively straightforward to remove the extra base (first letter of column 4) in the second type of output:</p>
  
  <pre><code># just a workaround to encolose the second file in a data frame
  # you can just read your file as a table using fread(), read.csv(), ...
  test &lt;- data.frame(
    col1 = "chr1",
    col2 = 100,
    col3 = ".",
    col4 = "GAAA",
    col5 = "G",
    stringsAsFactors = FALSE
  )
  
  &gt; test
    col1 col2 col3 col4 col5
  1 chr1  100    . GAAA    G
  
  # remove the first letter in column 4
  test<span class="math-container">$col4 &lt;- substring(test$</span>col4, 2)
  # converting column 4 to "-"
  test$col5 &lt;- "-"
  
  &gt; test
    col1 col2 col3 col4 col5
  1 chr1  100    .  AAA    -
  </code></pre>
  
  <p>EDIT:</p>
  
  <p>Here is how it can be done with <code>awk</code> for speed and memory concerns: The logic is the same as above, remove the first letter in column 4 and then change column 5 to "-".</p>
  
  <pre><code>awk '{<span class="math-container">$4 = substr($</span>4,2); print}' infile &gt; outfile
  awk '{$5 = "-"; print}' outfile &gt; outfile2
  </code></pre>
  
  <p>infile</p>
  
  <pre><code>chr1 100 . GAAA G
  </code></pre>
  
  <p>outfile</p>
  
  <pre><code>chr1 100 . AAA G
  </code></pre>
  
  <p>outfile2</p>
  
  <pre><code>chr1 100 . AAA -
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-19T11:59:08.840Z
Answers.Text: Thanks but my real VCF is several GB in size so I don't think this will work.
Answers.UserDisplayName: Nils
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-19T13:22:33.483Z
Answers.Text: I have edited my answer so as to include a solution making use of awk.
Answers.UserDisplayName: haci
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-19T10:12:42.853Z
Answers.LastActivityDate: 2019-08-19T13:20:03.430Z
Answers.LastEditDate: 2019-08-19T13:20:03.430Z
Answers.UserDisplayName: haci
Answers.Body: <p>Edited version of <a href="https://bioinformatics.stackexchange.com/users/7230/namshin-kim">Namshin's</a> code this can handle if REF or ALT is '-' ( these records in vcf file are observed when there is insertion/deletion).
  Added documentation in the script to explain code block I have modified.
  Hope this useful.
  Tested example with GRCh37</p>
  <pre><code>python fix_vcf.py -f genome.fa -o out_fixed.vcf input.vcf
  </code></pre>
  <p>example input.vcf:</p>
  <pre><code>##fileformat=VCFv4.2
  #CHROM  POS ID  REF ALT QUAL  FILTER  INFO
  7 6027157 . - T 1 PASS  NS=1  GQ  10
  9 98218616  . - C 1 PASS  NS=1  GQ  10
  17  41245200  . AT  - 1 PASS  NS=1  GQ  10
  13  32929213  . C - 1 PASS  NS=1  GQ  10
  
  </code></pre>
  <p>out_fixed.vcf:</p>
  <pre><code>##fileformat=VCFv4.2
  ##FILTER=&lt;ID=PASS,Description=&quot;All filters passed&quot;&gt;
  #CHROM  POS ID  REF ALT QUAL  FILTER  INFO
  7 6027157 . T TT  1 PASS  NS=1
  9 98218616  . A AC  1 PASS  NS=1
  17  41245199  . GAT G 1 PASS  NS=1
  13  32929212  . CC  C 1 PASS  NS=1
  </code></pre>
  <pre><code># -*- coding: utf-8 -*-
  import argparse
  import sys
  
  import pysam
  
  
  class Application:
      def __init__(self):
          self.args = Application.get_args()
          self.vcf = pysam.VariantFile(sys.stdin)
          self.fasta = pysam.FastaFile(self.args.fasta)
  
      @staticmethod
      def get_args() -&gt; argparse.Namespace:
          &quot;&quot;&quot;
          Read command line arguments and set input and output sources.
  
          :return: parsed command line arguments
          &quot;&quot;&quot;
  
          parser = argparse.ArgumentParser(prog=&quot;fixvcf.py&quot;, description=&quot;Fixes deletion represented by -&quot;)
          parser.add_argument('--version', action='version', version='%(prog)s 0.1')
  
          parser.add_argument(&quot;input&quot;, help=&quot;input file, use - to read from stdin&quot;)
          parser.add_argument(&quot;-f&quot;, &quot;--fasta&quot;, help=&quot;fasta reference file&quot;, required=True)
          parser.add_argument(&quot;-o&quot;, &quot;--output&quot;, help=&quot;output file&quot;)
  
          if len(sys.argv) == 1:
              parser.print_help(sys.stderr)
              sys.exit(1)
  
          args = parser.parse_args()
  
          if args.output:
              sys.stdout = open(args.output, &quot;w&quot;)
  
          if args.input != &quot;-&quot;:
              sys.stdin = open(args.input, &quot;r&quot;)
  
          return args
  
      def fix_record(self, record: pysam.libcbcf.VariantRecord) -&gt;     pysam.libcbcf.VariantRecord:
          &quot;&quot;&quot;
          If the ALT column of the records contains a `-`, the variant position is shift one position to the left.
          For reaching this the reference base for the position is determined and prepended to the current REF bases.
          The ALT value `-` is replaced with the determined ref base on position before. In case there are multiple ALT
          values the determined ref base is prepended to them.
  
          If the REF column of the records contains a `-`, the variant position will change.
          For reaching this the reference base for the position is determined and prepended to the current ALT bases.
          The REF value `-` is replaced with the determined ref base on position. In case there are multiple ALT
          values the determined ref base is prepended to them.
  
          :param record: vcf file record
          :return: fixed vcf record
          &quot;&quot;&quot;
  
          if &quot;-&quot; in record.alts:
              ref = self.fasta.fetch(reference=record.chrom, start=record.pos - 2, end=record.pos -1)
  
              record.pos = record.pos - 1
              record.ref = f&quot;{ref}{record.ref}&quot;
              record.alts = tuple(map(lambda alt: ref if alt == &quot;-&quot; else f&quot;{ref}{alt}&quot;, record.alts))
  
          if &quot;-&quot; in record.ref:
              ref = self.fasta.fetch(reference=record.chrom, start=record.pos - 1, end=record.pos)
  
              record.pos = record.pos
              record.ref = f&quot;{ref}&quot;
              record.alts = tuple(map(lambda alt: f&quot;{ref}{alt}&quot;, record.alts))
  
          return record
  
      def start(self):
          &quot;&quot;&quot;
          Print the header of the vcf file. Afterwards the fix_record method is applied to each record in the vcf file.
  
          For more information about python's map() see: 
  https://docs.python.org/3.6/library/functions.html#map
  
          For more information about the unpacking mechanism using `*`see:
          https://docs.python.org/3/tutorial/controlflow.html#tut-unpacking-arguments
          &quot;&quot;&quot;
  
          print(self.vcf.header, end=&quot;&quot;)
          #print(*map(self.fix_record, self.vcf), sep=&quot;&quot;, end=&quot;&quot;)
          for line in self.vcf:
              print(self.fix_record(line), sep=&quot;&quot;, end=&quot;&quot;)
  
  if __name__ == &quot;__main__&quot;:
      app = Application()
      app.start()
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-10T18:10:51.370Z
Answers.LastActivityDate: 2021-03-11T12:42:28.637Z
Answers.LastEditDate: 2021-03-11T12:42:28.637Z
Answers.UserDisplayName: Shriram Bhosle
Answers.Body: <p>One more thing. If empty ALT allele is not "-", you can change it such as "*", as follows.</p>
  
  <pre><code>    if "*" in record.alts:
          ref = self.fasta.fetch(reference=record.chrom, start=record.pos - 1, end=record.pos)
          record.pos = record.pos - 1
          record.ref = f"{ref}{record.ref}"
          record.alts = tuple(map(lambda alt: ref if alt == "*" else f"{ref}{alt}", record.alts))
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-02-20T11:54:29.217Z
Answers.Text: Hi Namshin, thanks for contributing, but this is not the way we usually answer questions on this website. You should not assume that a reader reads the whole thread. If it's an extension for a different answer, meaning which one and also explain what is the benefit of your extension. Note you can [[edit]] your answer.
Answers.UserDisplayName: Kamil S Jaron
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-02-16T02:07:04.343Z
Answers.LastActivityDate: 2020-02-16T02:07:04.343Z
Answers.UserDisplayName: Namshin Kim
Answers.Body: <p>This is my first post and I will add some explanations. When I tried to use this script, <code>print(*map(self.fix_record, self.vcf), sep=&quot;&quot;, end=&quot;&quot;)</code>, it will increase memory usage because it will load everything into memory and then start to apply fix_record function. So, I just used two lines <code>for line in self.vcf: print(self.fix_record(line), sep=&quot;&quot;, end=&quot;&quot;)</code>. Because <code>pysam</code> uses generator by default, if we process one by one by pysam's <code>VariantFile</code> function, it will consume very little memory. In my case, the VCF file was more than 200GB, so I had to fix this script for my VCF file.</p>
  <p>Second my VCF file used &quot;*&quot; for empty ALT, so I fixed two lines (1) <code>if &quot;*&quot; in record.alts:</code> (2) <code>record.alts = tuple(map(lambda alt: ref if alt == &quot;*&quot; else f&quot;{ref}{alt}&quot;, record.alts))</code></p>
  <pre><code>#!/usr/bin/env python
  # -*- coding: utf-8 -*-
  import argparse
  import sys
  
  import pysam
  
  
  class Application:
      def __init__(self):
          self.args = Application.get_args()
          self.vcf = pysam.VariantFile(sys.stdin)
          self.fasta = pysam.FastaFile(self.args.fasta)
  
      @staticmethod
      def get_args() -&gt; argparse.Namespace:
          &quot;&quot;&quot;
          Read command line arguments and set input and output sources.
  
          :return: parsed command line arguments
          &quot;&quot;&quot;
  
          parser = argparse.ArgumentParser(prog=&quot;fixvcf.py&quot;, description=&quot;Fixes deletion represented by -&quot;)
          parser.add_argument('--version', action='version', version='%(prog)s 0.1')
  
          parser.add_argument(&quot;input&quot;, help=&quot;input file, use - to read from stdin&quot;)
          parser.add_argument(&quot;-f&quot;, &quot;--fasta&quot;, help=&quot;fasta reference file&quot;, required=True)
          parser.add_argument(&quot;-o&quot;, &quot;--output&quot;, help=&quot;output file&quot;)
  
          if len(sys.argv) == 1:
              parser.print_help(sys.stderr)
              sys.exit(1)
  
          args = parser.parse_args()
  
          if args.output:
              sys.stdout = open(args.output, &quot;w&quot;)
  
          if args.input != &quot;-&quot;:
              sys.stdin = open(args.input, &quot;r&quot;)
  
          return args
  
      def fix_record(self, record: pysam.libcbcf.VariantRecord) -&gt;     pysam.libcbcf.VariantRecord:
          &quot;&quot;&quot;
          If the ALT column of the records contains a `-`, the variant position is shift one position to the left.
          For reaching this the reference base for the position is determined and prepended to the current REF bases.
          The ALT value `-` is replaced with the determined ref base on position before. In case there are multiple ALT
          values the determined ref base is prepended to them.
  
          :param record: vcf file record
          :return: fixed vcf record
          &quot;&quot;&quot;
  
          if &quot;*&quot; in record.alts:
              ref = self.fasta.fetch(reference=record.chrom, start=record.pos - 1, end=record.pos)
  
              record.pos = record.pos - 1
              record.ref = f&quot;{ref}{record.ref}&quot;
              record.alts = tuple(map(lambda alt: ref if alt == &quot;*&quot; else f&quot;{ref}{alt}&quot;, record.alts))
  
          return record
  
      def start(self):
          &quot;&quot;&quot;
          Print the header of the vcf file. Afterwards the fix_record method is applied to each record in the vcf file.
  
          For more information about python's map() see: 
  https://docs.python.org/3.6/library/functions.html#map
  
          For more information about the unpacking mechanism using `*`see:
          https://docs.python.org/3/tutorial/controlflow.html#tut-unpacking-arguments
          &quot;&quot;&quot;
  
          print(self.vcf.header, end=&quot;&quot;)
          #print(*map(self.fix_record, self.vcf), sep=&quot;&quot;, end=&quot;&quot;)
          for line in self.vcf:
              print(self.fix_record(line), sep=&quot;&quot;, end=&quot;&quot;)
  
  if __name__ == &quot;__main__&quot;:
      app = Application()
      app.start()
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-02-22T23:45:42.910Z
Answers.LastActivityDate: 2020-07-09T18:19:35.523Z
Answers.LastEditDate: 2020-07-09T18:19:35.523Z
Answers.UserDisplayName: Namshin Kim
Answers.Body: <p>According to the <a href="http://samtools.github.io/hts-specs/VCFv4.3.pdf" rel="nofollow noreferrer">specs</a> the ALT is not allowed to contain <code>-</code>. While technically supported, 'N' as the alternative allele is sometimes used unnecessarily and this script can also fix those cases if one exchanges the two &quot;-&quot; within the fix_record function for &quot;N&quot;.</p>
  <p>Here is a little python (&gt;=3.6) script that is able to fix it. It makes use of the pysam module. You need a reference file and this fasta file must be indexed by <code>samtools faidx reference.fa</code>. <strike>Please note that it doesn't support multiple values in the ALT column for records that contain a <code>-</code>.</strike></p>
  <p><strong>Usage:</strong></p>
  <pre><code>python fixvcf.py -f reference.fasta -o out.vcf in.vcf
  </code></pre>
  <p><strong>The script:</strong></p>
  <pre class="lang-py prettyprint-override"><code>#!/usr/bin/env python
  # -*- coding: utf-8 -*-
  import argparse
  import sys
  
  import pysam
  
  
  class Application:
      def __init__(self):
          self.args = Application.get_args()
          self.vcf = pysam.VariantFile(sys.stdin)
          self.fasta = pysam.FastaFile(self.args.fasta)
  
      @staticmethod
      def get_args() -&gt; argparse.Namespace:
          &quot;&quot;&quot;
          Read command line arguments and set input and output sources.
  
          :return: parsed command line arguments
          &quot;&quot;&quot;
          parser = argparse.ArgumentParser(prog=&quot;fixvcf.py&quot;, description=&quot;Fixes deletion represented by -&quot;)
          parser.add_argument('--version', action='version', version='%(prog)s 0.1')
  
          parser.add_argument(&quot;input&quot;, help=&quot;input file, use - to read from stdin&quot;)
          parser.add_argument(&quot;-f&quot;, &quot;--fasta&quot;, help=&quot;fasta reference file&quot;, required=True)
          parser.add_argument(&quot;-o&quot;, &quot;--output&quot;, help=&quot;output file&quot;)
  
          if len(sys.argv) == 1:
              parser.print_help(sys.stderr)
              sys.exit(1)
  
          args = parser.parse_args()
  
          if args.output:
              sys.stdout = open(args.output, &quot;w&quot;)
  
          if args.input != &quot;-&quot;:
              sys.stdin = open(args.input, &quot;r&quot;)
  
          return args
  
      def fix_record(self, record: pysam.libcbcf.VariantRecord) -&gt; pysam.libcbcf.VariantRecord:
          &quot;&quot;&quot;
          If the ALT column of the records contains a `-`, the variant position is shift one position to the left.
          For reaching this the reference base for the position is determined and prepended to the current REF bases.
          The ALT value `-` is replaced with the determined ref base on position before. In case there are multiple ALT
          values the determined ref base is prepended to them.
  
          :param record: vcf file record
          :return: fixed vcf record
          &quot;&quot;&quot;
          if &quot;-&quot; in record.alts:
              ref = self.fasta.fetch(region=f&quot;{record.chrom}:{record.pos - 1}-{record.pos - 1}&quot;)    
              record.pos = record.pos - 1
              record.ref = f&quot;{ref}{record.ref}&quot;
              record.alts = tuple(map(lambda alt: ref if alt == &quot;-&quot; else f&quot;{ref}{alt}&quot;, record.alts))
  
          return record
  
      def start(self):
          &quot;&quot;&quot;
          Print the header of the vcf file. Afterwards the fix_record method is applied to each record in the vcf file.
  
          For more information about python's map() see: https://docs.python.org/3.6/library/functions.html#map
  
          For more information about the unpacking mechanism using `*`see:
          https://docs.python.org/3/tutorial/controlflow.html#tut-unpacking-arguments
          &quot;&quot;&quot;
          print(self.vcf.header, end=&quot;&quot;)
          print(*map(self.fix_record, self.vcf), sep=&quot;&quot;, end=&quot;&quot;)
  
  
  if __name__ == &quot;__main__&quot;:
      app = Application()
      app.start()
  </code></pre>
  <p>A lot of the code above is boilerplate for running a script on the command line. The critical code for the transformation is in the <code>fix_record</code> function. The relevant code is below, expanded, with line numbers and a description of each command.</p>
  <pre><code>[1]   ref = self.fasta.fetch(
            region=f&quot;{record.chrom}:{record.pos - 1}-{record.pos - 1}&quot;
        )
  [2]   record.pos = record.pos - 1
  [3]   record.ref = f&quot;{ref}{record.ref}&quot;
  [4]   record.alts = tuple(
            map(
                lambda alt: ref if alt == &quot;-&quot; else f&quot;{ref}{alt}&quot;,
                record.alts
            )
        )
  </code></pre>
  <ol>
  <li>This grabs the base preceding the inserted/deleted sequence.</li>
  <li>This corrects the position of the variant to account for prepending another nucleotide.</li>
  <li>This defines the new corrected REF allele: concatenate the base grabbed in [1] with the original REF allele</li>
  <li>Apply an anonymous (lambda) function to each ALT allele; the function will replace <code>-</code> with the base grabbed in [1], or preprend the base to the allele if it is not <code>-</code></li>
  </ol>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-20T14:59:58.700Z
Answers.Text: +1, thanks for sharing a working script. It might be even more helpful for innocent bystanders to emphasize and explain the code that does the actual transformation.
Answers.UserDisplayName: Daniel Standage
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-20T16:59:49.723Z
Answers.Text: Done by adding type hints and doc strings :)
Answers.UserDisplayName: finswimmer
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-20T17:16:15.120Z
Answers.Text: Sorry, I should have been more clear. My edit is more of what I had in mind. :-)
Answers.UserDisplayName: Daniel Standage
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-10-24T15:05:31.673Z
Answers.Text: Thanks finswimmer for the script. It's been very helpful to me. I would like to extend it for the case of REF alleles with "-" as in: *chr1 6029086 - A* to: *chr1 6029086 CA C* I have made the attempt to do it by extend this solution for other cases but couldn't find the right way to do it for all of them. For example in: *chr1 1684347 - CCT* I would change it to (REF would change to "C"(the position grabbed)+ALT and ALT would change to the position grabbed("C") which worked in the previous example): *chr1 1684347 CCCT C* But it's wrong cause actually should be like: *chr1 1684347 C CCCT* How
Answers.UserDisplayName: Dagsbio
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-02-16T01:15:00.510Z
Answers.Text: Generator version of the python script. It won't consume your memmory at all. #print(*map(self.fix_record, self.vcf), sep="", end="") for line in self.vcf: print(self.fix_record(line), sep="", end="")
Answers.UserDisplayName: Namshin Kim
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-20T04:29:47.187Z
Answers.LastActivityDate: 2023-01-25T11:30:21.040Z
Answers.LastEditDate: 2023-01-25T11:30:21.040Z
Answers.UserDisplayName: finswimmer
Body: <p>I have a VCF file that has deletions specified like this, with the REF allele containing only the deleted portion and the ALT allele just saying <code>-</code>:</p>
  
  <pre><code>chr1 101 . AAA -
  </code></pre>
  
  <p>I would like to combine this with another VCF in which deletions are specified like this, with REF and ALT both extended by 1bp to the left to ensure neither is empty:</p>
  
  <pre><code>chr1 100 . GAAA G
  </code></pre>
  
  <p>Is there a tool to convert from one of these representations to the other? I have already tried <code>vt normalize</code> and <code>bcftools norm</code> but neither of them seem to do this.</p>
  
  <p>I don't really mind which representation I end up with although I think the second is the one more consistent with the spec.</p>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2019-08-19T13:45:58.670Z
Comments.Text: Cross-posted on biostars: https://www.biostars.org/p/394866/
Comments.UserDisplayName: Ram RS
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2019-08-19T13:49:03.437Z
Comments.Text: OP, the first of the two representations is so outdated that most tools might error out. You're better off insisting on converting to format #2
Comments.UserDisplayName: Ram RS
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2019-08-19T14:25:53.487Z
Comments.Text: @RamRS I agree. Would definitely prefer a way to convert format 1 to format 2 than vice versa. The other way round could be done with a simple awk solution though, since it doesn't require knowledge of the reference sequence.
Comments.UserDisplayName: Nils
Tags: <vcf>
Title: Fix dash/empty ALT alleles for deletions in VCF
ThreadText: # Fix dash/empty ALT alleles for deletions in VCF
  
  (Asked by: username_0 on 2019-08-19)
  
  I have a VCF file that has deletions specified like this, with the REF allele containing only the deleted portion and the ALT allele just saying `-`:
  
  ```
  chr1 101 . AAA -
  
  ```
  
  I would like to combine this with another VCF in which deletions are specified like this, with REF and ALT both extended by 1bp to the left to ensure neither is empty:
  
  ```
  chr1 100 . GAAA G
  
  ```
  
  Is there a tool to convert from one of these representations to the other? I have already tried `vt normalize` and `bcftools norm` but neither of them seem to do this.
  
  I don't really mind which representation I end up with although I think the second is the one more consistent with the spec.
  
  **Tags:** vcf
  
  > **Comments:**
  > **username_1**: Cross-posted on biostars: https://www.biostars.org/p/394866/  
  > **username_1**: OP, the first of the two representations is so outdated that most tools might error out. You're better off insisting on converting to format #2  
  > **username_0**: @username_1 I agree. Would definitely prefer a way to convert format 1 to format 2 than vice versa. The other way round could be done with a simple awk solution though, since it doesn't require knowledge of the reference sequence.  
  
  ---
  
  ## 5 answers
  
  ### Answer by username_6 on 2019-08-20. Score: 6 | Accepted answer
  
  According to the [specs](http://samtools.github.io/hts-specs/VCFv4.3.pdf) the ALT is not allowed to contain `-`. While technically supported, 'N' as the alternative allele is sometimes used unnecessarily and this script can also fix those cases if one exchanges the two "-" within the fix\_record function for "N".
  
  Here is a little python (>=3.6) script that is able to fix it. It makes use of the pysam module. You need a reference file and this fasta file must be indexed by `samtools faidx reference.fa`. Please note that it doesn't support multiple values in the ALT column for records that contain a `-`.
  
  **Usage:**
  
  ```
  python fixvcf.py -f reference.fasta -o out.vcf in.vcf
  
  ```
  
  **The script:**
  
  ```py
  #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  import argparse
  import sys
  
  import pysam
  
  class Application:
      def __init__(self):
          self.args = Application.get_args()
          self.vcf = pysam.VariantFile(sys.stdin)
          self.fasta = pysam.FastaFile(self.args.fasta)
  
      @staticmethod
      def get_args() -> argparse.Namespace:
          """
          Read command line arguments and set input and output sources.
  
          :return: parsed command line arguments
          """
          parser = argparse.ArgumentParser(prog="fixvcf.py", description="Fixes deletion represented by -")
          parser.add_argument('--version', action='version', version='%(prog)s 0.1')
  
          parser.add_argument("input", help="input file, use - to read from stdin")
          parser.add_argument("-f", "--fasta", help="fasta reference file", required=True)
          parser.add_argument("-o", "--output", help="output file")
  
          if len(sys.argv) == 1:
              parser.print_help(sys.stderr)
              sys.exit(1)
  
          args = parser.parse_args()
  
          if args.output:
              sys.stdout = open(args.output, "w")
  
          if args.input != "-":
              sys.stdin = open(args.input, "r")
  
          return args
  
      def fix_record(self, record: pysam.libcbcf.VariantRecord) -> pysam.libcbcf.VariantRecord:
          """
          If the ALT column of the records contains a `-`, the variant position is shift one position to the left.
          For reaching this the reference base for the position is determined and prepended to the current REF bases.
          The ALT value `-` is replaced with the determined ref base on position before. In case there are multiple ALT
          values the determined ref base is prepended to them.
  
          :param record: vcf file record
          :return: fixed vcf record
          """
          if "-" in record.alts:
              ref = self.fasta.fetch(region=f"{record.chrom}:{record.pos - 1}-{record.pos - 1}")    
              record.pos = record.pos - 1
              record.ref = f"{ref}{record.ref}"
              record.alts = tuple(map(lambda alt: ref if alt == "-" else f"{ref}{alt}", record.alts))
  
          return record
  
      def start(self):
          """
          Print the header of the vcf file. Afterwards the fix_record method is applied to each record in the vcf file.
  
          For more information about python's map() see: https://docs.python.org/3.6/library/functions.html#map
  
          For more information about the unpacking mechanism using `*`see:
          https://docs.python.org/3/tutorial/controlflow.html#tut-unpacking-arguments
          """
          print(self.vcf.header, end="")
          print(*map(self.fix_record, self.vcf), sep="", end="")
  
  if __name__ == "__main__":
      app = Application()
      app.start()
  
  ```
  
  A lot of the code above is boilerplate for running a script on the command line. The critical code for the transformation is in the `fix_record` function. The relevant code is below, expanded, with line numbers and a description of each command.
  
  ```
  [1]   ref = self.fasta.fetch(
            region=f"{record.chrom}:{record.pos - 1}-{record.pos - 1}"
        )
  [2]   record.pos = record.pos - 1
  [3]   record.ref = f"{ref}{record.ref}"
  [4]   record.alts = tuple(
            map(
                lambda alt: ref if alt == "-" else f"{ref}{alt}",
                record.alts
            )
        )
  
  ```
  
  1. This grabs the base preceding the inserted/deleted sequence.
  2. This corrects the position of the variant to account for prepending another nucleotide.
  3. This defines the new corrected REF allele: concatenate the base grabbed in [1] with the original REF allele
  4. Apply an anonymous (lambda) function to each ALT allele; the function will replace `-` with the base grabbed in [1], or preprend the base to the allele if it is not `-`
  
  > **Comments:**
  > **username_7**: +1, thanks for sharing a working script. It might be even more helpful for innocent bystanders to emphasize and explain the code that does the actual transformation.  
  > **username_6**: Done by adding type hints and doc strings :)  
  > **username_7**: Sorry, I should have been more clear. My edit is more of what I had in mind. :-)  
  > **username_8**: Thanks username_6 for the script. It's been very helpful to me. I would like to extend it for the case of REF alleles with "-" as in: *chr1 6029086 - A* to: *chr1 6029086 CA C* I have made the attempt to do it by extend this solution for other cases but couldn't find the right way to do it for all of them. For example in: *chr1 1684347 - CCT* I would change it to (REF would change to "C"(the position grabbed)+ALT and ALT would change to the position grabbed("C") which worked in the previous example): *chr1 1684347 CCCT C* But it's wrong cause actually should be like: *chr1 1684347 C CCCT* How  
  > **username_4**: Generator version of the python script. It won't consume your memmory at all. #print(*map(self.fix_record, self.vcf), sep="", end="") for line in self.vcf: print(self.fix_record(line), sep="", end="")  
  
  ---
  
  ### Answer by username_2 on 2019-08-19. Score: 1
  
  Probably it is better to use dedicated tools, however, here is a quick R workaround. It is relatively straightforward to remove the extra base (first letter of column 4) in the second type of output:
  
  ```
  # just a workaround to encolose the second file in a data frame
  # you can just read your file as a table using fread(), read.csv(), ...
  test <- data.frame(
    col1 = "chr1",
    col2 = 100,
    col3 = ".",
    col4 = "GAAA",
    col5 = "G",
    stringsAsFactors = FALSE
  )
  
  > test
    col1 col2 col3 col4 col5
  1 chr1  100    . GAAA    G
  
  # remove the first letter in column 4
  test$col4 <- substring(test$col4, 2)
  # converting column 4 to "-"
  test$col5 <- "-"
  
  > test
    col1 col2 col3 col4 col5
  1 chr1  100    .  AAA    -
  
  ```
  
  EDIT:
  
  Here is how it can be done with `awk` for speed and memory concerns: The logic is the same as above, remove the first letter in column 4 and then change column 5 to "-".
  
  ```
  awk '{$4 = substr($4,2); print}' infile > outfile
  awk '{$5 = "-"; print}' outfile > outfile2
  
  ```
  
  infile
  
  ```
  chr1 100 . GAAA G
  
  ```
  
  outfile
  
  ```
  chr1 100 . AAA G
  
  ```
  
  outfile2
  
  ```
  chr1 100 . AAA -
  
  ```
  
  > **Comments:**
  > **username_0**: Thanks but my real VCF is several GB in size so I don't think this will work.  
  > **username_2**: I have edited my answer so as to include a solution making use of awk.  
  
  ---
  
  ### Answer by username_4 on 2020-02-16. Score: 1
  
  One more thing. If empty ALT allele is not "-", you can change it such as "\*", as follows.
  
  ```
      if "*" in record.alts:
          ref = self.fasta.fetch(reference=record.chrom, start=record.pos - 1, end=record.pos)
          record.pos = record.pos - 1
          record.ref = f"{ref}{record.ref}"
          record.alts = tuple(map(lambda alt: ref if alt == "*" else f"{ref}{alt}", record.alts))
  
  ```
  
  > **Comments:**
  > **username_5**: Hi username_4, thanks for contributing, but this is not the way we usually answer questions on this website. You should not assume that a reader reads the whole thread. If it's an extension for a different answer, meaning which one and also explain what is the benefit of your extension. Note you can [[edit]] your answer.  
  
  ---
  
  ### Answer by username_4 on 2020-02-22. Score: 1
  
  This is my first post and I will add some explanations. When I tried to use this script, `print(*map(self.fix_record, self.vcf), sep="", end="")`, it will increase memory usage because it will load everything into memory and then start to apply fix\_record function. So, I just used two lines `for line in self.vcf: print(self.fix_record(line), sep="", end="")`. Because `pysam` uses generator by default, if we process one by one by pysam's `VariantFile` function, it will consume very little memory. In my case, the VCF file was more than 200GB, so I had to fix this script for my VCF file.
  
  Second my VCF file used "\*" for empty ALT, so I fixed two lines (1) `if "*" in record.alts:` (2) `record.alts = tuple(map(lambda alt: ref if alt == "*" else f"{ref}{alt}", record.alts))`
  
  ```
  #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  import argparse
  import sys
  
  import pysam
  
  class Application:
      def __init__(self):
          self.args = Application.get_args()
          self.vcf = pysam.VariantFile(sys.stdin)
          self.fasta = pysam.FastaFile(self.args.fasta)
  
      @staticmethod
      def get_args() -> argparse.Namespace:
          """
          Read command line arguments and set input and output sources.
  
          :return: parsed command line arguments
          """
  
          parser = argparse.ArgumentParser(prog="fixvcf.py", description="Fixes deletion represented by -")
          parser.add_argument('--version', action='version', version='%(prog)s 0.1')
  
          parser.add_argument("input", help="input file, use - to read from stdin")
          parser.add_argument("-f", "--fasta", help="fasta reference file", required=True)
          parser.add_argument("-o", "--output", help="output file")
  
          if len(sys.argv) == 1:
              parser.print_help(sys.stderr)
              sys.exit(1)
  
          args = parser.parse_args()
  
          if args.output:
              sys.stdout = open(args.output, "w")
  
          if args.input != "-":
              sys.stdin = open(args.input, "r")
  
          return args
  
      def fix_record(self, record: pysam.libcbcf.VariantRecord) ->     pysam.libcbcf.VariantRecord:
          """
          If the ALT column of the records contains a `-`, the variant position is shift one position to the left.
          For reaching this the reference base for the position is determined and prepended to the current REF bases.
          The ALT value `-` is replaced with the determined ref base on position before. In case there are multiple ALT
          values the determined ref base is prepended to them.
  
          :param record: vcf file record
          :return: fixed vcf record
          """
  
          if "*" in record.alts:
              ref = self.fasta.fetch(reference=record.chrom, start=record.pos - 1, end=record.pos)
  
              record.pos = record.pos - 1
              record.ref = f"{ref}{record.ref}"
              record.alts = tuple(map(lambda alt: ref if alt == "*" else f"{ref}{alt}", record.alts))
  
          return record
  
      def start(self):
          """
          Print the header of the vcf file. Afterwards the fix_record method is applied to each record in the vcf file.
  
          For more information about python's map() see: 
  https://docs.python.org/3.6/library/functions.html#map
  
          For more information about the unpacking mechanism using `*`see:
          https://docs.python.org/3/tutorial/controlflow.html#tut-unpacking-arguments
          """
  
          print(self.vcf.header, end="")
          #print(*map(self.fix_record, self.vcf), sep="", end="")
          for line in self.vcf:
              print(self.fix_record(line), sep="", end="")
  
  if __name__ == "__main__":
      app = Application()
      app.start()
  
  ```
  
  
  ---
  
  ### Answer by username_3 on 2021-03-10. Score: 0
  
  Edited version of [username_4's](https://bioinformatics.stackexchange.com/users/7230/username_4) code this can handle if REF or ALT is '-' ( these records in vcf file are observed when there is insertion/deletion).
  Added documentation in the script to explain code block I have modified.
  Hope this useful.
  Tested example with GRCh37
  
  ```
  python fix_vcf.py -f genome.fa -o out_fixed.vcf input.vcf
  
  ```
  
  example input.vcf:
  
  ```
  ##fileformat=VCFv4.2
  #CHROM  POS ID  REF ALT QUAL  FILTER  INFO
  7 6027157 . - T 1 PASS  NS=1  GQ  10
  9 98218616  . - C 1 PASS  NS=1  GQ  10
  17  41245200  . AT  - 1 PASS  NS=1  GQ  10
  13  32929213  . C - 1 PASS  NS=1  GQ  10
  
  ```
  
  out\_fixed.vcf:
  
  ```
  ##fileformat=VCFv4.2
  ##FILTER=<ID=PASS,Description="All filters passed">
  #CHROM  POS ID  REF ALT QUAL  FILTER  INFO
  7 6027157 . T TT  1 PASS  NS=1
  9 98218616  . A AC  1 PASS  NS=1
  17  41245199  . GAT G 1 PASS  NS=1
  13  32929212  . CC  C 1 PASS  NS=1
  
  ```
  
  ```
  # -*- coding: utf-8 -*-
  import argparse
  import sys
  
  import pysam
  
  class Application:
      def __init__(self):
          self.args = Application.get_args()
          self.vcf = pysam.VariantFile(sys.stdin)
          self.fasta = pysam.FastaFile(self.args.fasta)
  
      @staticmethod
      def get_args() -> argparse.Namespace:
          """
          Read command line arguments and set input and output sources.
  
          :return: parsed command line arguments
          """
  
          parser = argparse.ArgumentParser(prog="fixvcf.py", description="Fixes deletion represented by -")
          parser.add_argument('--version', action='version', version='%(prog)s 0.1')
  
          parser.add_argument("input", help="input file, use - to read from stdin")
          parser.add_argument("-f", "--fasta", help="fasta reference file", required=True)
          parser.add_argument("-o", "--output", help="output file")
  
          if len(sys.argv) == 1:
              parser.print_help(sys.stderr)
              sys.exit(1)
  
          args = parser.parse_args()
  
          if args.output:
              sys.stdout = open(args.output, "w")
  
          if args.input != "-":
              sys.stdin = open(args.input, "r")
  
          return args
  
      def fix_record(self, record: pysam.libcbcf.VariantRecord) ->     pysam.libcbcf.VariantRecord:
          """
          If the ALT column of the records contains a `-`, the variant position is shift one position to the left.
          For reaching this the reference base for the position is determined and prepended to the current REF bases.
          The ALT value `-` is replaced with the determined ref base on position before. In case there are multiple ALT
          values the determined ref base is prepended to them.
  
          If the REF column of the records contains a `-`, the variant position will change.
          For reaching this the reference base for the position is determined and prepended to the current ALT bases.
          The REF value `-` is replaced with the determined ref base on position. In case there are multiple ALT
          values the determined ref base is prepended to them.
  
          :param record: vcf file record
          :return: fixed vcf record
          """
  
          if "-" in record.alts:
              ref = self.fasta.fetch(reference=record.chrom, start=record.pos - 2, end=record.pos -1)
  
              record.pos = record.pos - 1
              record.ref = f"{ref}{record.ref}"
              record.alts = tuple(map(lambda alt: ref if alt == "-" else f"{ref}{alt}", record.alts))
  
          if "-" in record.ref:
              ref = self.fasta.fetch(reference=record.chrom, start=record.pos - 1, end=record.pos)
  
              record.pos = record.pos
              record.ref = f"{ref}"
              record.alts = tuple(map(lambda alt: f"{ref}{alt}", record.alts))
  
          return record
  
      def start(self):
          """
          Print the header of the vcf file. Afterwards the fix_record method is applied to each record in the vcf file.
  
          For more information about python's map() see: 
  https://docs.python.org/3.6/library/functions.html#map
  
          For more information about the unpacking mechanism using `*`see:
          https://docs.python.org/3/tutorial/controlflow.html#tut-unpacking-arguments
          """
  
          print(self.vcf.header, end="")
          #print(*map(self.fix_record, self.vcf), sep="", end="")
          for line in self.vcf:
              print(self.fix_record(line), sep="", end="")
  
  if __name__ == "__main__":
      app = Application()
      app.start()
  
  ```
  
  
  ---
  
  