diff --git a/.gitignore b/.gitignore index cf2eaec6..b23f4a22 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,6 @@ pip-log.txt # Unit test / coverage reports .coverage -coverage.* .tox nosetests.xml htmlcov diff --git a/README.md b/README.md index e7971810..e3e31e74 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![PyPI Version](https://img.shields.io/pypi/v/pyGenomeTracks.svg?style=plastic)](https://pypi.org/project/pyGenomeTracks/) [![bioconda-badge](https://img.shields.io/conda/vn/bioconda/pyGenomeTracks.svg?style=plastic)](https://anaconda.org/bioconda/pygenometracks) [![bioconda-badge](https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?style=plastic)](http://bioconda.github.io) [![Build Status](https://travis-ci.org/deeptools/pyGenomeTracks.svg?branch=master)](https://travis-ci.org/deeptools/pyGenomeTracks) - +![Coverage](./docs/coverage.svg) pyGenomeTracks ============== @@ -39,10 +39,15 @@ Installation ------------ pyGenomeTracks works with python >=3.6. -Currently, the best way to install pyGenomeTracks is with anaconda +The recommended way to install pyGenomeTracks is via conda + +```bash +$ conda create -n pygenometracks -c bioconda -c conda-forge pygenometracks python=3.7 +``` +To get a specific version, one can specify it. For example: ```bash -$ conda install -c bioconda -c conda-forge pygenometracks +$ conda create -n pygenometracks -c bioconda -c conda-forge pygenometracks=3.5 python=3.7 ``` Also, pyGenomeTracks can be installed using pip @@ -130,7 +135,7 @@ Documentation Our [documentation](http://pygenometracks.readthedocs.io/) provide [examples](http://pygenometracks.readthedocs.org/en/latest/content/examples.html), as well as the [full list of possible parameters](http://pygenometracks.readthedocs.org/en/latest/content/possible-parameters.html) and [guidelines for developers who would like to add a new track type](http://pygenometracks.readthedocs.org/en/latest/content/adding-new-tracks.html). - External users diff --git a/docs/content/all_default_properties_rst.txt b/docs/content/all_default_properties_rst.txt index 4bd06128..7b8d962a 100644 --- a/docs/content/all_default_properties_rst.txt +++ b/docs/content/all_default_properties_rst.txt @@ -3,7 +3,7 @@ parameter :doc:`tracks/x_axis` :doc:`tracks/epilogos` ========================= ========================= ========================= ========================= ========================= ========================= ========================= ========================= ========================= ========================= ========================= ========================= ========================= ========================= overlay_previous no no no no no no no no no no no no no where bottom left -fontsize 15 12 12 12 12 +fontsize 15 12 12 12 categories_file not set orientation not set not set not set not set not set not set not set not set not set not set not set links_type arcs @@ -15,6 +15,7 @@ max_value min_value not set not set not set not set not set not set not set not set ylim not set compact_arcs_level 0 +use_middle false false border_color black black black prefered_name transcript_name transcript_name transcript_name merge_transcripts false false false @@ -45,12 +46,11 @@ log_pseudocount y_axis_values transformed transformed second_file* not set not set operation* file file -use_middle false +grid false false rasterize false true true pos_score_in_bin center plot_horizontal_lines false colormap viridis RdYlBu_r -region not set depth 100000 show_masked_bins false scale_factor 1 diff --git a/docs/content/all_possible_properties.txt b/docs/content/all_possible_properties.txt index 181d7fbe..1bf04eac 100644 --- a/docs/content/all_possible_properties.txt +++ b/docs/content/all_possible_properties.txt @@ -24,6 +24,10 @@ - for *links*: 0, 1, 2 +- **use_middle**: + + - for *links, bedgraph*: true, false + - **merge_transcripts**: - for *domains, bed, gtf*: true, false @@ -94,9 +98,9 @@ - for *bigwig, bedgraph*: true, false -- **use_middle**: +- **grid**: - - for *bedgraph*: true, false + - for *bigwig, bedgraph*: true, false - **rasterize**: diff --git a/docs/content/all_tracks.rst b/docs/content/all_tracks.rst index 6992573b..e57b5e89 100644 --- a/docs/content/all_tracks.rst +++ b/docs/content/all_tracks.rst @@ -1,31 +1,20 @@ All available tracks ==================== - -:doc:`tracks/bed` - -:doc:`tracks/bedgraph` - -:doc:`tracks/bedgraph_matrix` - -:doc:`tracks/bigwig` - -:doc:`tracks/domains` - -:doc:`tracks/epilogos` - -:doc:`tracks/gtf` - -:doc:`tracks/hic_matrix` - -:doc:`tracks/hlines` - -:doc:`tracks/links` - -:doc:`tracks/narrow_peak` - -:doc:`tracks/scalebar` - -:doc:`tracks/spacer` - -:doc:`tracks/x_axis` +.. toctree:: + :maxdepth: 1 + + tracks/bed + tracks/bedgraph + tracks/bedgraph_matrix + tracks/bigwig + tracks/domains + tracks/epilogos + tracks/gtf + tracks/hic_matrix + tracks/hlines + tracks/links + tracks/narrow_peak + tracks/scalebar + tracks/spacer + tracks/x_axis diff --git a/docs/content/examples.rst b/docs/content/examples.rst index 94d02d1e..86a1d762 100644 --- a/docs/content/examples.rst +++ b/docs/content/examples.rst @@ -106,12 +106,18 @@ The output file of some 4C-seq pipeline are bedgraph where the coordinates are t .. literalinclude:: ../../pygenometracks/tests/test_data/bedgraph_useMid.ini :language: INI + +We can generate two zooms using a bed instead of regions: + +.. literalinclude:: ../../pygenometracks/tests/test_data/regions_imbricated_chr2.bed .. code:: bash - $ pyGenomeTracks --tracks bedgraph_useMid.ini --region chr2:73,800,000-75,744,000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o master_bedgraph_useMid.pdf + $ pyGenomeTracks --tracks bedgraph_useMid.ini --BED regions_imbricated_chr2.bed --trackLabelFraction 0.2 --width 38 --dpi 130 -o master_bedgraph_useMid.png + +.. image:: ../../pygenometracks/tests/test_data/master_bedgraph_useMid_chr2-73800000-75744000.png -The output is available `here `_. +.. image:: ../../pygenometracks/tests/test_data/master_bedgraph_useMid_chr2-74000000-74800000.png Examples with peaks @@ -268,7 +274,7 @@ The configuration file for this image is: Log transform and Operation Examples --------------------------- +------------------------------------ With the parameter ``operation`` you can make operations between one or two files (here two bigwig files but this is also working with two bedgraph files). For example, difference, log ratio, scaling... diff --git a/docs/content/installation.rst b/docs/content/installation.rst index 65cf21c7..a6f5ad7e 100644 --- a/docs/content/installation.rst +++ b/docs/content/installation.rst @@ -4,7 +4,7 @@ Installation Remember -- pyGenomeTracks is available for **command line usage** as well as for **integration into Galaxy servers**! -.. contents:: +.. contents:: :local: Requirements @@ -19,15 +19,20 @@ Requirements * matplotlib >= 3.1.1 * gffutils >=0.9 -The fastest way to obtain **Python 3.6 together with numpy** is -via the `Anaconda Scientific Python -Distribution `_. -Just download the version that's suitable for your operating system and -follow the directions for its installation. All of the requirements for pyGenomeTracks can be installed in Anaconda with: +Command line installation using ``conda`` +----------------------------------------- + +We encourage users to use ``conda`` installation to install pygenometracks. All of the requirements for pyGenomeTracks can be installed via Anaconda with: .. code:: bash - $ conda install -c bioconda -c conda-forge pygenometracks + $ conda create -n pygenometracks -c bioconda -c conda-forge pygenometracks python=3.7 + +To get a specific version, one can specify it. For example: + +.. code:: bash + + $ conda create -n pygenometracks -c bioconda -c conda-forge pygenometracks=3.5 python=3.7 Command line installation using ``pip`` ----------------------------------------- @@ -45,11 +50,10 @@ If you need to specify a specific path for the installation of the tools, make u $ pip install --install-option="--prefix=/MyPath/Tools/pyGenomeTracks" git+https://github.com/deeptools/pyGenomeTracks.git - Command line installation without ``pip`` ------------------------------------------- -You are highly recommended to use `pip` rather than these more complicated steps. +You are highly recommended to use `conda install` rather than the following complicated steps. 1. Install the requirements listed above in the "requirements" section. This is done automatically by `pip`. diff --git a/docs/content/releases.rst b/docs/content/releases.rst index 4f2007d9..3f0ae1a7 100644 --- a/docs/content/releases.rst +++ b/docs/content/releases.rst @@ -1,28 +1,21 @@ Releases ======== -:doc:`releases/3.4` -""""""""""""""""""" -:doc:`releases/3.3` -""""""""""""""""""" -:doc:`releases/3.2.1` -""""""""""""""""""""" -:doc:`releases/3.2` -""""""""""""""""""" -:doc:`releases/3.1.2` -""""""""""""""""""""" -:doc:`releases/3.1.1` -""""""""""""""""""""" -:doc:`releases/3.1` -""""""""""""""""""" -:doc:`releases/3.0` -""""""""""""""""""" -:doc:`releases/2.1` -""""""""""""""""""" -:doc:`releases/2.0` -""""""""""""""""""" -:doc:`releases/1.0` -""""""""""""""""""" +.. toctree:: + :maxdepth: 1 + + releases/3.5 + releases/3.4 + releases/3.3 + releases/3.2.1 + releases/3.2 + releases/3.1.2 + releases/3.1.1 + releases/3.1 + releases/3.0 + releases/2.1 + releases/2.0 + releases/1.0 Main changes in configuration files: Since v3.2: diff --git a/docs/content/releases/3.3.rst b/docs/content/releases/3.3.rst index 833fdc09..414f73c8 100644 --- a/docs/content/releases/3.3.rst +++ b/docs/content/releases/3.3.rst @@ -2,25 +2,31 @@ === Release 3.3 adds: +^^^^^^^^^^^^^^^^^ - a documentation on readthedocs: https://pygenometracks.readthedocs.io - progress bar for bed, gtf, bedgraph, narrowPeak, epilogos - all colors can be set as ``(r, g, b)`` with r, g, b values between 0 and 1. - all colormap can be set as an array of colors, for example ``[red, white, (0, 0, 0.5)]`` - the titles on the right can be align left, right or center with the argument ``--trackLabelHAlign`` -- for the links track, + +- for the links track - ``compact_arcs_level`` to be able to see both very long arcs and very small arcs. - ``ylim`` to be able to zoom and see small arcs. + - a new track type: ``file_type = scalebar`` which by default is close to the UCSC scale bar. -- for the bed tracks: + +- for the bed tracks - a new gene type: ``tssarrow`` - ``border_color`` and ``color_utr`` can be set to ``bed_rgb``. - ``all_labels_inside`` allow to put the name of the region on the left if it ends after the plotted region. - ``labels_in_margin`` allow to put the name of the region in the margin if it ends after the plotted region. + - ``line_width`` can now be set in the narrowPeak tracks. - ``colormap`` can now be set in bedgraphMatrix tracks. bug fixes: +^^^^^^^^^^ - if a bed with no interval is provided, pgt no longer exit. - When an exon had both UTR start and UTR end within it, only the UTR start was considered. diff --git a/docs/content/releases/3.4.rst b/docs/content/releases/3.4.rst index 20aa1c20..cf3c2ce2 100644 --- a/docs/content/releases/3.4.rst +++ b/docs/content/releases/3.4.rst @@ -2,22 +2,32 @@ === Improved documentation: +^^^^^^^^^^^^^^^^^^^^^^^ - fix url of test_data thanks to @sonnynguyen - Better documentation for pyGenomeTracks / makeTracksFile - Documentation of each track Enhancements: +^^^^^^^^^^^^^ - Different bed files format (BED3, BED4, BED5, BED6, BED8, BED9, BED12) is guessed based on the first line and rely not only on number of columns but on the type of each column (string/float etc.). This way, broadPeaks/gappedPeaks and other bed-like formats can be accepted as ``file_type = bed`` without preprocessing. + - gtf has now its own ``file_type``. **Warning**:``file_type = bed`` for gtf will be no longer supported in a future version. + - You can use a decreasing x-axis (from larger coordinates to smaller coordinates) with the option ``--decreasingXAxis`` in ``pyGenomeTracks``. + - For bedgraph and bigwig: - - logScale: To apply a log transformation to your data you can set ``transform`` to ``log1p``, ``log``, ``log2``, ``log10``, ``-log``. For others than ``log1p``, you can set a ``log_pseudocount``. By default the y axis values will represent the transformed values and the transformation will be written on the left of the y axis but you can decide to keep the original values by setting ``y_axis_values = original``. - - operation on files: You can plot the result of an operation on one or two files without preprocessing. To use it, put the operation in ``operation`` with the variable ``file`` or both variables ``file`` and ``second_file``, for example ``operation = 0.89 * file`` or ``operation = max(file, second_file)`` or ``operation = file - second_file``. In the two later cases, you need to put the path of the second file in ``second_file``. However, this operation can be time consuming if you do it multiple times and you may prefer to convert your files in advance. -For more examples on these two new features, visit `the examples `_. + + - logScale: To apply a log transformation to your data you can set ``transform`` to ``log1p``, ``log``, ``log2``, ``log10``, ``-log``. For others than ``log1p``, you can set a ``log_pseudocount``. By default the y axis values will represent the transformed values and the transformation will be written on the left of the y axis but you can decide to keep the original values by setting ``y_axis_values = original``. + + - operation on files: You can plot the result of an operation on one or two files without preprocessing. To use it, put the operation in ``operation`` with the variable ``file`` or both variables ``file`` and ``second_file``, for example ``operation = 0.89 * file`` or ``operation = max(file, second_file)`` or ``operation = file - second_file``. In the two later cases, you need to put the path of the second file in ``second_file``. However, this operation can be time consuming if you do it multiple times and you may prefer to convert your files in advance. + + For more examples on these two new features, visit `the examples `_. + - Both ``type = line`` and ``type = lines`` are working in bedgraph_matrix Bugfix: +^^^^^^^ - In version 3.3, if you were using a colormap in bed the ``border_color`` and ``color_utr`` were ignored. Now each one can be set to different color/colormap/bed_rgb. diff --git a/docs/content/releases/3.5.rst b/docs/content/releases/3.5.rst new file mode 100644 index 00000000..b4bedb9a --- /dev/null +++ b/docs/content/releases/3.5.rst @@ -0,0 +1,63 @@ +3.5 +=== + +Enhancements: +^^^^^^^^^^^^^ + +- pyGenomeTracks goes much faster: + + - We now use bedtools to load only a portion of bed, gtf, bedgraph, narrowPeak, bedgraphMatrix, Epilogos, links. This speeds up the process dramatically especially for gtf files. + + - When you use a cool matrix, only the plotted region is loaded, this speeds up the process. If multiple regions on different chromosomes are provided in a BED this option is not used. + + - Unfortunately, it is not possible to speed the process with h5 matrices so you may want to convert them to cool with `hicConvertFormat `_. + +- pyGenomeTracks does not require sorted bed anymore. + +- For coverage tracks (bedgraph and bigwig), there is a new parameter: ``grid`` which allows to display horizontal lines. + +- For links, you can choose to use the middle of start1 and end1 and the middle of start2 and end2 thanks to ``use_middle`` instead of the extremities coordinates. + +- For Hi-C matrices, mcool files are now supported. + +- For vlines, the line_width can now be set. + +Minor enhancements: +^^^^^^^^^^^^^^^^^^^ + +- Bedgraph with NA values in the 4-th column do not raise error anymore. + +- There is a progress bar for links. + +- For Hi-C matrices, + + - there is no error when the plot goes over the chromosome size provided by the matrix. + + - if the depth is smaller than binsize it makes an empty plot instead of raising errors. + +- When the ``overlay_previous`` is set in the first track it is ignored and a warning is given instead of giving an error with a not meaningful error message. + +- The color for negative values in coverage tracks (bigwig and bedgraph) is now part of the output of ``make_tracks_file``. + +- Others output of ``make_tracks_file`` have been modified for better clarity. + +- Others code related enhancements which are transparent to the users. + +- The format of bed12 is more stringent (the blocks must span the chromStart and chromEnd). + +- Improve the documentation regarding the installation. We highly recommand to use conda. + +Bugfixes: +^^^^^^^^^ + +- For bed tracks when ``gene_rows`` or ``global_max_row`` was set the last row was very close to the bottom (sometimes even overlaying the next track). Now it is vertically centered and do not go over the track height. + +- Solve some bugs how non conventional bed files are handle. + +- Display more meaningful error messages. + +- Only plot scale bar when in the region of plot. + +- Do not show a warning when file_type is set for ``x_axis`` or ``spacer``. + +- Solve some incompatibilities with python 3.8. However, python 3.8 is not officially supported by now as bioconda do not support it yet ``_. diff --git a/docs/content/tracks/auto/bed_options_text.txt b/docs/content/tracks/auto/bed_options_text.txt index ec76ff4d..40b48a4f 100644 --- a/docs/content/tracks/auto/bed_options_text.txt +++ b/docs/content/tracks/auto/bed_options_text.txt @@ -5,8 +5,9 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes # If the bed file contains the exon @@ -14,8 +15,8 @@ height = 2 # a region **with direction** is plotted. # If the bed file contains a column for color (column 9), then this color can be used by # setting: -# color = bed_rgb -#if color is a valid colormap name (like RbBlGn), then the score is mapped +#color = bed_rgb +# if color is a valid colormap name (like RbBlGn), then the score (column 5) is mapped # to the colormap. # In this case, the the min_value and max_value for the score can be provided, otherwise # the maximum score and minimum score found are used. @@ -24,8 +25,6 @@ height = 2 #max_value=100 # If the color is simply a color name, then this color is used and the score is not considered. color = darkblue -# height of track in cm -height = 5 # whether printing the labels labels = false # optional: @@ -37,21 +36,24 @@ fontsize = 10 # optional: line_width #line_width = 0.5 # the display parameter defines how the bed file is plotted. -# The options are ['collapsed', 'interleaved', 'triangles'] These options asume that the regions do not overlap. +# Default is 'stacked' where regions are plotted on different lines so +# we can see all regions and all labels. +# The other options are ['collapsed', 'interleaved', 'triangles'] +# These options assume that the regions do not overlap. # `collapsed`: The bed regions are plotted one after the other in one line. # `interleaved`: The bed regions are plotted in two lines, first up, then down, then up etc. -# if display is not given, then each region is plotted using the gene style # optional, default is black. To remove the border, simply set 'border_color' to none # Not used in tssarrow style #border_color = black -# style to plot the genes when they have exon information +# style to plot the genes when the display is not triangles #style = UCSC #style = flybase #style = tssarrow # maximum number of gene rows to be plotted. This # field is useful to limit large number of close genes # to be printed over many rows. When several images want -# to be combined this must be set to get equal size, otherwise, on each image the height of each gene changes +# to be combined this must be set to get equal size +# otherwise, on each image the height of each gene changes #gene_rows = 10 # by default the ymax is the number of # rows occupied by the genes in the region plotted. However, @@ -81,9 +83,6 @@ fontsize = 10 # If you want that the tip of the arrow correspond to # the extremity of the interval use: # arrowhead_included = true -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale -#overlay_previous = yes # optional. If not given is guessed from the file ending. file_type = bed \ No newline at end of file diff --git a/docs/content/tracks/auto/bedgraph_deduced_from_code.txt b/docs/content/tracks/auto/bedgraph_deduced_from_code.txt index 9b39c5fc..35c47bb7 100644 --- a/docs/content/tracks/auto/bedgraph_deduced_from_code.txt +++ b/docs/content/tracks/auto/bedgraph_deduced_from_code.txt @@ -20,6 +20,8 @@ Optional: - **min_value**: by default this option is not set but you can also put: any float +- **use_middle**: `false` (default) or true. + - **show_data_range**: `true` (default) or false. - **type**: `fill` (default) @@ -42,7 +44,7 @@ Optional: - **operation\***: `file` (default) -- **use_middle**: `false` (default) or true. +- **grid**: `false` (default) or true. - **rasterize**: `false` (default) or true. diff --git a/docs/content/tracks/auto/bedgraph_matrix_options_text.txt b/docs/content/tracks/auto/bedgraph_matrix_options_text.txt index 3e438106..d8d2f32f 100644 --- a/docs/content/tracks/auto/bedgraph_matrix_options_text.txt +++ b/docs/content/tracks/auto/bedgraph_matrix_options_text.txt @@ -5,8 +5,9 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes # a bedgraph matrix file is like a bedgraph, except that per bin there @@ -23,7 +24,8 @@ type = lines # If the type is not lines, you can choose to keep the matrix as not rasterized # (only used if you use pdf or svg output format) by using: # rasterize = false -# The different options for color maps can be found here: https://matplotlib.org/users/colormaps.html +# The different options for color maps can be found here: +# https://matplotlib.org/users/colormaps.html # the default color map is viridis # If you want your own colormap you can put the values of the color you want # For example, colormap = ['blue', 'yellow', 'red'] diff --git a/docs/content/tracks/auto/bedgraph_options_text.txt b/docs/content/tracks/auto/bedgraph_options_text.txt index 42f8473d..45846c12 100644 --- a/docs/content/tracks/auto/bedgraph_options_text.txt +++ b/docs/content/tracks/auto/bedgraph_options_text.txt @@ -5,16 +5,19 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes color = green +# To use a different color for negative values +#negative_color = red # To use transparency, you can use alpha # default is 1 # alpha = 0.5 # the default for min_value and max_value is 'auto' which means that the scale will go -# from the minimum value found in the region plotted to the maximum value found. +# roughly from the minimum value found in the region plotted to the maximum value found. min_value = 0 #max_value = auto # to convert missing data (NaNs) into zeros. Otherwise, missing data is not plotted. @@ -68,5 +71,7 @@ show_data_range = true # gives the transformed values, if you prefer to see # the original values: #y_axis_values = original +# If you want to have a grid on the y-axis +#grid = true file_type = bedgraph \ No newline at end of file diff --git a/docs/content/tracks/auto/bigwig_deduced_from_code.txt b/docs/content/tracks/auto/bigwig_deduced_from_code.txt index 9a73bf4f..538a989d 100644 --- a/docs/content/tracks/auto/bigwig_deduced_from_code.txt +++ b/docs/content/tracks/auto/bigwig_deduced_from_code.txt @@ -42,6 +42,8 @@ Optional: - **operation\***: `file` (default) +- **grid**: `false` (default) or true. + \* While pyGenomeTracks can convert coverage tracks on the fly, this might be a time-consuming step, especially on large files and if you want to replot many times. In this situation, we recommend using the deepTools suite to convert your files in advance. For example `bamCoverage `_ or `bamCompare `_ \ No newline at end of file diff --git a/docs/content/tracks/auto/bigwig_options_text.txt b/docs/content/tracks/auto/bigwig_options_text.txt index 2770e719..4e04e584 100644 --- a/docs/content/tracks/auto/bigwig_options_text.txt +++ b/docs/content/tracks/auto/bigwig_options_text.txt @@ -5,19 +5,23 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes color = #666666 +# To use a different color for negative values +#negative_color = red # To use transparency, you can use alpha # default is 1 # alpha = 0.5 # the default for min_value and max_value is 'auto' which means that the scale will go -# from the minimum value found in the region plotted to the maximum value found. +# roughly from the minimum value found in the region plotted to the maximum value found. min_value = 0 #max_value = auto -# The number of bins takes the region to be plotted and divides it into the number of bins specified +# The number of bins takes the region to be plotted and divides it +# into the number of bins specified # Then, at each bin the bigwig mean value is computed and plotted. # A lower number of bins produces a coarser tracks number_of_bins = 700 @@ -60,5 +64,7 @@ show_data_range = true # gives the transformed values, if you prefer to see # the original values: #y_axis_values = original +# If you want to have a grid on the y-axis +#grid = true file_type = bigwig \ No newline at end of file diff --git a/docs/content/tracks/auto/domains_deduced_from_code.txt b/docs/content/tracks/auto/domains_deduced_from_code.txt index 0edb6be3..ac43aab7 100644 --- a/docs/content/tracks/auto/domains_deduced_from_code.txt +++ b/docs/content/tracks/auto/domains_deduced_from_code.txt @@ -10,8 +10,6 @@ Optional: - **overlay_previous**: `no` (default) or yes or share-y. -- **fontsize**: `12` (default) or any float above 0 - - **orientation**: by default this option is not set but you can also put: inverted. - **line_width**: `0.5` (default) or any float above 0 diff --git a/docs/content/tracks/auto/domains_options_text.txt b/docs/content/tracks/auto/domains_options_text.txt index ec76ff4d..c0331cb2 100644 --- a/docs/content/tracks/auto/domains_options_text.txt +++ b/docs/content/tracks/auto/domains_options_text.txt @@ -5,17 +5,15 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes -# If the bed file contains the exon -# structure (bed 12) then this is plotted. Otherwise -# a region **with direction** is plotted. # If the bed file contains a column for color (column 9), then this color can be used by # setting: -# color = bed_rgb -#if color is a valid colormap name (like RbBlGn), then the score is mapped +#color = bed_rgb +# if color is a valid colormap name (like RbBlGn), then the score (column 5) is mapped # to the colormap. # In this case, the the min_value and max_value for the score can be provided, otherwise # the maximum score and minimum score found are used. @@ -24,66 +22,10 @@ height = 2 #max_value=100 # If the color is simply a color name, then this color is used and the score is not considered. color = darkblue -# height of track in cm -height = 5 -# whether printing the labels -labels = false -# optional: -# by default the labels are not printed if you have more than 60 features. -# to change it, just increase the value: -#max_labels = 60 -# optional: font size can be given to override the default size -fontsize = 10 # optional: line_width #line_width = 0.5 -# the display parameter defines how the bed file is plotted. -# The options are ['collapsed', 'interleaved', 'triangles'] These options asume that the regions do not overlap. -# `collapsed`: The bed regions are plotted one after the other in one line. -# `interleaved`: The bed regions are plotted in two lines, first up, then down, then up etc. -# if display is not given, then each region is plotted using the gene style # optional, default is black. To remove the border, simply set 'border_color' to none -# Not used in tssarrow style #border_color = black -# style to plot the genes when they have exon information -#style = UCSC -#style = flybase -#style = tssarrow -# maximum number of gene rows to be plotted. This -# field is useful to limit large number of close genes -# to be printed over many rows. When several images want -# to be combined this must be set to get equal size, otherwise, on each image the height of each gene changes -#gene_rows = 10 -# by default the ymax is the number of -# rows occupied by the genes in the region plotted. However, -# by setting this option, the global maximum is used instead. -# This is useful to combine images that are all consistent and -# have the same number of rows. -#global_max_row = true -# If you want to plot all labels inside the plotting region: -#all_labels_inside = true -# If you want to display the name of the gene which goes over the plotted -# region in the right margin put: -#labels_in_margin = true -# if you use UCSC style, you can set the relative distance between 2 arrows on introns -# default is 2 -#arrow_interval = 2 -# if you use tssarrow style, you can choose the length of the arrow in bp -# (default is 4% of the plotted region) -#arrow_length = 5000 -# if you use flybase or tssarrow style, you can choose the color of non-coding intervals: -#color_utr = grey -# as well as the proportion between their height and the one of coding -# (by default they are the same height): -#height_utr = 1 -# By default, for oriented intervals in flybase style, -# or bed files with less than 12 columns, the arrowhead is added -# outside of the interval. -# If you want that the tip of the arrow correspond to -# the extremity of the interval use: -# arrowhead_included = true -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale -#overlay_previous = yes -# optional. If not given is guessed from the file ending. -file_type = bed +# optional. If not given it is guessed from the file ending. +file_type = domains \ No newline at end of file diff --git a/docs/content/tracks/auto/epilogos_options_text.txt b/docs/content/tracks/auto/epilogos_options_text.txt index df04bea8..dde74a2d 100644 --- a/docs/content/tracks/auto/epilogos_options_text.txt +++ b/docs/content/tracks/auto/epilogos_options_text.txt @@ -5,8 +5,9 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes # The categories file should contain the color information for each category id diff --git a/docs/content/tracks/auto/gtf_options_text.txt b/docs/content/tracks/auto/gtf_options_text.txt index b2ff970a..b5dfed1b 100644 --- a/docs/content/tracks/auto/gtf_options_text.txt +++ b/docs/content/tracks/auto/gtf_options_text.txt @@ -5,8 +5,9 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes # By default the transcript_name is used. @@ -30,21 +31,24 @@ fontsize = 10 # optional: line_width #line_width = 0.5 # the display parameter defines how the gtf file is plotted. -# The options are ['collapsed', 'interleaved', 'triangles'] These options asume that the regions do not overlap. +# Default is 'stacked' where regions are plotted on different lines so +# we can see all regions and all labels. +# The other options are ['collapsed', 'interleaved', 'triangles'] +# These options assume that the regions do not overlap. # `collapsed`: The gtf regions are plotted one after the other in one line. # `interleaved`: The gtf regions are plotted in two lines, first up, then down, then up etc. -# if display is not given, then each region is plotted using the gene style # optional, default is black. To remove the border, simply set 'border_color' to none # Not used in tssarrow style #border_color = black -# style to plot the genes when they have exon information +# style to plot the genes when the display is not triangles #style = UCSC #style = flybase #style = tssarrow # maximum number of gene rows to be plotted. This # field is useful to limit large number of close genes # to be printed over many rows. When several images want -# to be combined this must be set to get equal size, otherwise, on each image the height of each gene changes +# to be combined this must be set to get equal size +# otherwise, on each image the height of each gene changes #gene_rows = 10 # by default the ymax is the number of # rows occupied by the genes in the region plotted. However, @@ -74,9 +78,6 @@ fontsize = 10 # If you want that the tip of the arrow correspond to # the extremity of the interval use: # arrowhead_included = true -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale -#overlay_previous = yes # optional. If not given is guessed from the file ending. file_type = gtf \ No newline at end of file diff --git a/docs/content/tracks/auto/hic_matrix_deduced_from_code.txt b/docs/content/tracks/auto/hic_matrix_deduced_from_code.txt index 5b429b9e..0e1581dc 100644 --- a/docs/content/tracks/auto/hic_matrix_deduced_from_code.txt +++ b/docs/content/tracks/auto/hic_matrix_deduced_from_code.txt @@ -22,8 +22,6 @@ Optional: - **colormap**: `RdYlBu_r` (default) -- **region**: by default this option is not set - - **depth**: `100000` (default) or any integer above 1 - **show_masked_bins**: `false` (default) or true. diff --git a/docs/content/tracks/auto/hic_matrix_options_text.txt b/docs/content/tracks/auto/hic_matrix_options_text.txt index 74aafaf4..45ab861e 100644 --- a/docs/content/tracks/auto/hic_matrix_options_text.txt +++ b/docs/content/tracks/auto/hic_matrix_options_text.txt @@ -1,6 +1,6 @@ -title = -# The different options for color maps can be found here: https://matplotlib.org/users/colormaps.html +# The different options for color maps can be found here: +# https://matplotlib.org/users/colormaps.html # the default color map is RdYlBu_r (_r) stands for reverse # If you want your own colormap you can put the values of the color you want # For example, colormap = ['blue', 'yellow', 'red'] @@ -10,7 +10,8 @@ title = # If it is more than 125% of the plotted region, it will # be adjsted to this maximum value. depth = 100000 -# height of track (in cm) can be given. Otherwise, the height is computed such that the proportions of the +# height of track (in cm) can be given. +# Otherwise, the height is computed such that the proportions of the # hic matrix are kept (e.g. the image does not appear shrink or extended) # height = 10 # min_value and max_value refer to the contacts in the matrix. @@ -23,8 +24,6 @@ transform = log1p # the default is to extend neighboring bins to # obtain an aesthetically pleasant output show_masked_bins = false -# if you want to plot the track upside-down: -# orientation = inverted # optional if the values in the matrix need to be scaled the # following parameter can be used. This is useful to plot multiple hic-matrices on the same scale # scale_factor = 1 diff --git a/docs/content/tracks/auto/hlines_options_text.txt b/docs/content/tracks/auto/hlines_options_text.txt index cdfb5169..53ea30ec 100644 --- a/docs/content/tracks/auto/hlines_options_text.txt +++ b/docs/content/tracks/auto/hlines_options_text.txt @@ -5,8 +5,9 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes # color of the lines @@ -14,6 +15,10 @@ color = black # To use transparency, you can use alpha # default is 1 # alpha = 0.5 +# the default for min_value and max_value is 'auto' which means that the scale will go +# roughly from the minimum value found in the region plotted to the maximum value found. +min_value = 0 +#max_value = auto # line width: # line_width = 0.5 # options for line_style are 'solid', 'dashed', 'dotted', and 'dashdot' diff --git a/docs/content/tracks/auto/links_deduced_from_code.txt b/docs/content/tracks/auto/links_deduced_from_code.txt index 1523e2f8..859c9412 100644 --- a/docs/content/tracks/auto/links_deduced_from_code.txt +++ b/docs/content/tracks/auto/links_deduced_from_code.txt @@ -30,3 +30,5 @@ Optional: - **compact_arcs_level**: `0` (default) or 1 or 2. +- **use_middle**: `false` (default) or true. + diff --git a/docs/content/tracks/auto/links_options_text.txt b/docs/content/tracks/auto/links_options_text.txt index ea215862..69164a83 100644 --- a/docs/content/tracks/auto/links_options_text.txt +++ b/docs/content/tracks/auto/links_options_text.txt @@ -5,8 +5,9 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes # the file format for links is (tab separated) @@ -18,13 +19,16 @@ height = 2 # depending on the value of links_type either 'arcs' or 'triangles' or 'loops' can be plotted. # If arcs, a line will be drawn from the center of the first region (chr1: 150), # to the center of the other region (chr1: 275). -# if triangles, the vertix of the triangle will be drawn at the center between the two points (also the center of -# each position is used) +# if triangles, the vertix of the triangle will be drawn at the center between the two points +# (also the extremity of each position is used) # if loops, a rectangle highlighting the intersection between the 2 regions will be shown # the triangles, and loops options are convenient to overlay over a # Hi-C matrix to highlight the matrix pixel of the highlighted link # For these tracks do not hesitate to put large line_width like 5 or 10. links_type = arcs +# For triangles and arcs, by default the extremities coordinates are used +# To use the middle of start1 and end1 and the middle of start2 and end2 +#use_middle = true # color of the lines color = red # if color is a valid colormap name (like RdYlGn), diff --git a/docs/content/tracks/auto/narrow_peak_options_text.txt b/docs/content/tracks/auto/narrow_peak_options_text.txt index eef3022e..8e98007e 100644 --- a/docs/content/tracks/auto/narrow_peak_options_text.txt +++ b/docs/content/tracks/auto/narrow_peak_options_text.txt @@ -5,8 +5,9 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes color = #FF000080 diff --git a/docs/content/tracks/auto/scalebar_options_text.txt b/docs/content/tracks/auto/scalebar_options_text.txt index e6e2dddf..20cec025 100644 --- a/docs/content/tracks/auto/scalebar_options_text.txt +++ b/docs/content/tracks/auto/scalebar_options_text.txt @@ -5,8 +5,9 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes # color of the scalebar diff --git a/docs/content/tracks/auto/spacer_options_text.txt b/docs/content/tracks/auto/spacer_options_text.txt index e1201b84..5628419a 100644 --- a/docs/content/tracks/auto/spacer_options_text.txt +++ b/docs/content/tracks/auto/spacer_options_text.txt @@ -5,6 +5,7 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes diff --git a/docs/content/tracks/auto/x_axis_options_text.txt b/docs/content/tracks/auto/x_axis_options_text.txt index e1201b84..5628419a 100644 --- a/docs/content/tracks/auto/x_axis_options_text.txt +++ b/docs/content/tracks/auto/x_axis_options_text.txt @@ -5,6 +5,7 @@ title = height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes diff --git a/docs/content/tracks/bedgraph_matrix.rst b/docs/content/tracks/bedgraph_matrix.rst index 8265724b..7134e695 100644 --- a/docs/content/tracks/bedgraph_matrix.rst +++ b/docs/content/tracks/bedgraph_matrix.rst @@ -1,5 +1,5 @@ bedgraph_matrix -========== +=============== Description ----------- diff --git a/docs/content/tracks/narrow_peak.rst b/docs/content/tracks/narrow_peak.rst index 7ee8fa1c..c78bae90 100644 --- a/docs/content/tracks/narrow_peak.rst +++ b/docs/content/tracks/narrow_peak.rst @@ -1,5 +1,5 @@ narrow_peak -========== +=========== Description ----------- diff --git a/docs/coverage.svg b/docs/coverage.svg new file mode 100644 index 00000000..0fa96494 --- /dev/null +++ b/docs/coverage.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + coverage + coverage + 98% + 98% + + diff --git a/environment.yml b/environment.yml index 07265480..da9796ed 100644 --- a/environment.yml +++ b/environment.yml @@ -11,10 +11,11 @@ dependencies: - intervaltree >=2.1.0 - pybigwig >=0.3.16 - future >=0.17.0 - - hicmatrix >=12 + - hicmatrix >=13 - pysam >=0.14 - pytest - gffutils >=0.9 + - pybedtools >=0.8.1 - tqdm >=4.20 - pip: - "git+https://github.com/deeptools/pyGenomeTracks.git" diff --git a/examples/BedMatrixExampleTrack.py b/examples/BedMatrixExampleTrack.py index ddca0efe..55d0cd3d 100644 --- a/examples/BedMatrixExampleTrack.py +++ b/examples/BedMatrixExampleTrack.py @@ -10,18 +10,18 @@ class BedGraphMatrixTrack(BedGraphTrack): # we can re-use the code for reading a bedgraph file SUPPORTED_ENDINGS = ['.bm', '.bm.gz'] TRACK_TYPE = 'bedgraph_matrix' - OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + """ - # a bedgraph matrix file is like a bedgraph, except that per bin there - # are more than one value (separated by tab). This file type is - # produced by the HiCExplorer tool hicFindTads and contains - # the TAD-separation score at different window sizes. - # E.g. - # chrX 18279 40131 0.399113 0.364118 0.320857 0.274307 - # chrX 40132 54262 0.479340 0.425471 0.366541 0.324736 - #min_value = 0.10 - #max_value = 0.70 - file_type = {} - """.format(TRACK_TYPE) + OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + f""" +# a bedgraph matrix file is like a bedgraph, except that per bin there +# are more than one value (separated by tab). This file type is +# produced by the HiCExplorer tool hicFindTads and contains +# the TAD-separation score at different window sizes. +# E.g. +# chrX 18279 40131 0.399113 0.364118 0.320857 0.274307 +# chrX 40132 54262 0.479340 0.425471 0.366541 0.324736 +#min_value = 0.10 +#max_value = 0.70 +file_type = {TRACK_TYPE} +""" DEFAULTS_PROPERTIES = {'max_value': None, 'min_value': None, 'show_data_range': True, diff --git a/pygenometracks/_version.py b/pygenometracks/_version.py index 5a4358dd..1027b84a 100644 --- a/pygenometracks/_version.py +++ b/pygenometracks/_version.py @@ -2,4 +2,4 @@ # This file is originally generated from Git information by running 'setup.py # version'. Distribution tarballs contain a pre-generated copy of this file. -__version__ = '3.4' +__version__ = '3.5' diff --git a/pygenometracks/getAllDefaultsAndPossible.py b/pygenometracks/getAllDefaultsAndPossible.py index 554bed32..43ace338 100644 --- a/pygenometracks/getAllDefaultsAndPossible.py +++ b/pygenometracks/getAllDefaultsAndPossible.py @@ -65,9 +65,10 @@ def main(): all_default_parameters[p][track_type] = value has_default = False for p, value in track_class.DEFAULTS_PROPERTIES.items(): - all_default_parameters[p] = all_default_parameters.get(p, {}) - all_default_parameters[p][track_type] = value - has_default = True + if p != 'region': + all_default_parameters[p] = all_default_parameters.get(p, {}) + all_default_parameters[p][track_type] = value + has_default = True if has_default: all_tracks_with_default += [track_type] @@ -112,7 +113,7 @@ def main(): max_char = max([len(mat[i, j]) for i in range(mat.shape[0]) for j in range(mat.shape[1])]) mat[1, :] = ['=' * max_char] * mat.shape[1] np.savetxt(os.path.join("docs", "content", "all_default_properties_rst.txt"), - mat, fmt='%-{}s'.format(max_char), delimiter=" ", + mat, fmt=f'%-{max_char}s', delimiter=" ", header=' '.join(mat[1, :]), footer=' '.join(mat[1, :]), comments='') if starPut: diff --git a/pygenometracks/makeTracksFile.py b/pygenometracks/makeTracksFile.py index 82565f4b..821b2de2 100644 --- a/pygenometracks/makeTracksFile.py +++ b/pygenometracks/makeTracksFile.py @@ -29,7 +29,7 @@ def parse_arguments(args=None): required=False) parser.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version=f'%(prog)s {__version__}') return parser @@ -57,12 +57,11 @@ def main(args=None): for ending in track_class.SUPPORTED_ENDINGS: if file_h.name.endswith(ending): default_values = track_class.OPTIONS_TXT - default_values = default_values.replace("title =", "title = {}".format(label)) - args.out.write("\n[{label}]\nfile = {file}\n{default_values}". - format(label=label, file=file_h.name, default_values=default_values)) + default_values = default_values.replace("title =", f"title = {label}") + args.out.write(f"\n[{label}]\nfile = {file_h.name}\n{default_values}") - sys.stdout.write("Adding {} file: {}\n".format(track_type, file_h.name)) + sys.stdout.write(f"Adding {track_type} file: {file_h.name}\n") track_added = True if track_added is False: - sys.stdout.write("WARNING: file format not recognized for: {}\n".format(file_h.name)) + sys.stdout.write(f"WARNING: file format not recognized for: {file_h.name}\n") diff --git a/pygenometracks/plotTracks.py b/pygenometracks/plotTracks.py index 05168eb4..d78bd30b 100644 --- a/pygenometracks/plotTracks.py +++ b/pygenometracks/plotTracks.py @@ -143,8 +143,7 @@ import sys import argparse -import matplotlib -matplotlib.use('Agg') +import warnings from pygenometracks.tracksClass import PlotTracks from pygenometracks._version import __version__ @@ -181,7 +180,7 @@ def parse_arguments(args=None): ) parser.add_argument('--width', - help='figure width in centimeters (default is {})'.format(DEFAULT_FIGURE_WIDTH), + help=f'figure width in centimeters (default is {DEFAULT_FIGURE_WIDTH})', type=float, default=DEFAULT_FIGURE_WIDTH) @@ -231,7 +230,7 @@ def parse_arguments(args=None): action='store_true') parser.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version=f'%(prog)s {__version__}') return parser @@ -244,28 +243,41 @@ def get_region(region_string): """ if region_string: # separate the chromosome name and the location using the ':' character - chrom, position = region_string.strip().split(":") + try: + chrom, position = region_string.strip().split(":") + except ValueError: + raise InputError(f"The region provided ({region_string})" + " is not valid, it should be chr:start-end.\n") # clean up the position for char in ",.;|!{}()": position = position.replace(char, '') position_list = position.split("-") + assert len(position_list) == 2, \ + f"The region provided ({region_string})" \ + " is not valid, it should be chr:start-end.\n" + try: region_start = int(position_list[0]) - except IndexError: - region_start = 0 + except ValueError: + raise InputError(f"The start value ({position_list[0]}) in the" + " region provided" + " is not valid, it should be chr:start-end.\n") try: region_end = int(position_list[1]) - except IndexError: - region_end = 1e15 # a huge number - if region_start < 0: - region_start = 0 + except ValueError: + raise InputError(f"The start value ({position_list[0]}) in the" + " region provided" + " is not valid, it should be chr:start-end.\n") + if region_end <= region_start: raise InputError("Please check that the region end is larger " "than the region start.\n" - "Values given:\nstart: {}\nend: {}" - "\n".format(region_start, region_end)) + f"Values given:\nstart: {region_start}\n" + f"end: {region_end}\n" + "To plot tracks with a decreasing axis " + "consider using `--decreasingXAxis`.") return chrom, region_start, region_end @@ -273,14 +285,11 @@ def get_region(region_string): def main(args=None): args = parse_arguments().parse_args(args) - trp = PlotTracks(args.tracks.name, args.width, fig_height=args.height, - fontsize=args.fontSize, dpi=args.dpi, - track_label_width=args.trackLabelFraction) + # Identify the regions to plot: if args.BED: - count = 0 + regions = [] for line in args.BED.readlines(): - count += 1 try: chrom, start, end = line.strip().split('\t')[0:3] except ValueError: @@ -288,27 +297,38 @@ def main(args=None): try: start, end = map(int, [start, end]) except ValueError as detail: - sys.stderr.write("Invalid value found at line\t{}\t. {}\n".format(line, detail)) - name = args.outFileName.split(".") - file_suffix = name[-1] - file_prefix = ".".join(name[:-1]) + warnings.warn(f"Invalid value found at line\t{line}\t. {detail}\n") + continue + regions.append((chrom, start, end)) + else: + regions = [get_region(args.region)] + + if len(regions) == 0: + raise InputError("There is no valid regions to plot.") + + # Create all the tracks + trp = PlotTracks(args.tracks.name, args.width, fig_height=args.height, + fontsize=args.fontSize, dpi=args.dpi, + track_label_width=args.trackLabelFraction, + plot_regions=regions) - file_name = "{}_{}-{}-{}.{}".format(file_prefix, chrom, start, end, file_suffix) + # Plot them + if args.BED: + name = args.outFileName.split(".") + file_suffix = name[-1] + file_prefix = ".".join(name[:-1]) + for chrom, start, end in regions: + file_name = f"{file_prefix}_{chrom}-{start}-{end}.{file_suffix}" if end - start < 200000: - sys.stderr.write("A region shorter than 200kb has been " - "detected! This can be too small to return " - "a proper TAD plot!\n") - # start -= 100000 - # start = max(0, start) - # end += 100000 - sys.stderr.write("saving {}\n".format(file_name)) - # print("{} {} {}".format(chrom, start, end)) + warnings.warn("A region shorter than 200kb has been " + "detected! This can be too small to return " + "a proper TAD plot!\n") + sys.stderr.write(f"saving {file_name}\n") trp.plot(file_name, chrom, start, end, title=args.title, h_align_titles=args.trackLabelHAlign, decreasing_x_axis=args.decreasingXAxis) else: - region = get_region(args.region) - trp.plot(args.outFileName, *region, title=args.title, + trp.plot(args.outFileName, *regions[0], title=args.title, h_align_titles=args.trackLabelHAlign, decreasing_x_axis=args.decreasingXAxis) trp.close_files() diff --git a/pygenometracks/readBed.py b/pygenometracks/readBed.py index cb45656e..9a1ccb90 100644 --- a/pygenometracks/readBed.py +++ b/pygenometracks/readBed.py @@ -38,9 +38,6 @@ def __init__(self, file_handle): else: self.get_bed_interval(fields, is_first_line=True) self.file_handle.seek(0) - self.prev_chrom = None - self.prev_start = -1 - self.prev_line = None # list of bed fields self.fields = ['chromosome', 'start', 'end', @@ -74,25 +71,6 @@ def get_no_comment_line(self): self.line_number += 1 return line - def next(self): - """ - :return: bedInterval object - """ - line = self.get_no_comment_line() - - bed = self.get_bed_interval(line) - if self.prev_chrom == bed.chromosome: - assert self.prev_start <= bed.start, \ - "Bed file not sorted. Please use a sorted bed file.\n" \ - "File: {}\n" \ - "Previous line: {}\n Current line{} ".format(self.file_handle.name, self.prev_line, line) - - self.prev_chrom = bed.chromosome - self.prev_start = bed.start - self.prev_line = line - - return bed - def __next__(self): """ :return: bedInterval object @@ -100,15 +78,6 @@ def __next__(self): line = self.get_no_comment_line() bed = self.get_bed_interval(line) - if self.prev_chrom == bed.chromosome: - assert self.prev_start <= bed.start, \ - "Bed file not sorted. Please use a sorted bed file.\n" \ - "File: {}\n" \ - "Previous line: {}\n Current line{} ".format(self.file_handle.name, self.prev_line, line) - - self.prev_chrom = bed.chromosome - self.prev_start = bed.start - self.prev_line = line return bed @@ -117,7 +86,7 @@ def get_bed_interval(self, bed_line, is_first_line=False): Processes each bed line from a bed file, casts the values and returns a namedtuple object - >>> bed_line="chr1\t0\t1000\tgene_1\t0.5\t-\t0\t1000\t0\t3\t10,20,100\t20,200,700" + >>> bed_line="chr1\t0\t1000\tgene_1\t0.5\t-\t0\t1000\t0\t3\t10,20,300\t0,200,700" >>> with open('/tmp/test.bed', 'w') as fh: ... foo = fh.write(bed_line) >>> bed_f = ReadBed(open('/tmp/test.bed','r')) @@ -125,7 +94,7 @@ def get_bed_interval(self, bed_line, is_first_line=False): >>> bed.chromosome 'chr1' >>> bed.block_starts - [20, 200, 700] + [0, 200, 700] >>> bed_line="chr2\t0\t1000\tgene_1\t0.5\t-\n" >>> with open('/tmp/test.bed', 'w') as fh: @@ -138,17 +107,20 @@ def get_bed_interval(self, bed_line, is_first_line=False): line_data = bed_line.strip() line_data = to_string(line_data) line_data = line_data.split("\t") + if is_first_line: + assert len(line_data) != 1, \ + "Only one field detected, you may use" \ + " a bed delimited by space. This format " \ + "is not supported by pyGenomeTracks." if not is_first_line: if self.file_type != 'bed6': # When bed6 you can have less fields in one row # because there are default values assert len(line_data) >= self.fields_to_read, \ - "File type detected is {} but line {}: {} does " \ - "not have {} fields.".format(self.file_type, - self.line_number, - bed_line, - self.fields_to_read) + f"File type detected is {self.file_type} but line" \ + f" {self.line_number}: {bed_line} does " \ + f"not have {self.fields_to_read} fields." line_data = line_data[:self.fields_to_read] line_values = [] @@ -167,10 +139,9 @@ def get_bed_interval(self, bed_line, is_first_line=False): r = '-' else: sys.stderr.write("*Warning, invalid strand value" - "found {} for line #{}:\n{}\n " + f"found {r} for line #{bed_line}:\n{self.line_number}\n " "Setting strand to '.'" - "\n".format(r, bed_line, - self.line_number)) + "\n") r = '.' line_values.append(r) @@ -179,43 +150,66 @@ def get_bed_interval(self, bed_line, is_first_line=False): try: line_values.append(int(r)) except ValueError: - raise InputError("Value: {} in field {} at line {}" + raise InputError(f"Value: {r} in field {idx + 1} at line" + f" {self.line_number}" " is not an integer. This is " "probably not a bed file." - "\n".format(r, idx + 1, - self.line_number)) - elif idx in [6, 7, 9]: - # thichStart(6), thickEnd(7) and blockCount(9) fields + "\n") + elif idx in [6, 7]: + # thichStart(6) and thickEnd(7) fields # Should be integer, if they are not we change the bed type try: line_values.append(int(r)) except ValueError: if is_first_line: - if idx == 9: - self.file_type = 'bed8' - self.fields_to_read = 8 - else: - self.file_type = 'bed6' - self.fields_to_read = 6 - sys.stderr.write("Value: {} in field {}" + self.file_type = 'bed6' + self.fields_to_read = 6 + sys.stderr.write(f"Value: {r} in field {idx + 1}" " is not an integer" - "\n Only the first {} fields will" - " be used.\n".format(r, idx + 1, - self.fields_to_read)) + "\n Only the first " + f"{self.fields_to_read} fields will" + " be used.\n") break else: - default_value = 0 if (idx == 9) else line_values[1] - sys.stderr.write("Value: {} in field {} at line {}" + if idx == 6: + default_value = line_values[1] + else: # idx is 7 + default_value = line_values[6] + line_values.append(default_value) + sys.stderr.write(f"Value: {r} in field {idx + 1} at" + f" line {self.line_number}" " is not an integer" - "\n {} will be used.\n" - "".format(r, idx + 1, - self.line_number, - default_value)) + f"\n {default_value} will be used.\n") + elif idx == 9: + # blockCount(9) field + # Should be integer, if they are not we change the bed type + try: + line_values.append(int(r)) + except ValueError: + if is_first_line: + self.file_type = 'bed8' + self.fields_to_read = 8 + sys.stderr.write(f"Value: {r} in field {idx + 1}" + " is not an integer" + "\n Only the first " + f"{self.fields_to_read} fields will" + " be used.\n") + break + else: + sys.stderr.write("Warning: reading line " + f"#{self.line_number}, " + f"the block number {r} is not " + "valid.\nNo block will be used.\n") + line_values.append(1) + line_values.append([line_values[2] - line_values[1]]) + line_values.append([0]) + break # check item rgb elif idx == 8: passed = True try: - line_values.append(int(r)) + # This is what happens in UCSC browser: + line_values.append([0, 0, int(r)]) except ValueError: r = to_string(r) rgb = r.split(",") @@ -231,20 +225,19 @@ def get_bed_interval(self, bed_line, is_first_line=False): if not passed: if is_first_line: sys.stderr.write("Warning: " - "The rgb field {} is not " + f"The rgb field {r} is not " "valid.\nOnly the first 8 fields" - " will be used.\n" - "".format(self.line_number, r)) + " will be used.\n") self.file_type = 'bed8' self.fields_to_read = 8 break else: - sys.stderr.write("Warning: reading line: #{}. " - "The rgb field {} is not " - "valid.\n0" - " will be used.\n" - "".format(self.line_number, r)) - line_values.append(0) + sys.stderr.write("Warning: reading line: " + f"#{self.line_number}. " + f"The rgb field {r} is not " + "valid.\n0,0,0" + " will be used.\n") + line_values.append([0, 0, 0]) elif idx in [10, 11]: # this are the block sizes and block start positions @@ -255,25 +248,23 @@ def get_bed_interval(self, bed_line, is_first_line=False): except ValueError as detail: if is_first_line: sys.stderr.write("Warning: " - "The block field {} is not " - "valid.\nError message: {}" + f"The block field {r} is not " + f"valid.\nError message: {detail}" "\nOnly the first 9 fields" - " will be used.\n" - "".format(r, - detail)) + " will be used.\n") self.file_type = 'bed9' self.fields_to_read = 9 break else: - sys.stderr.write("Warning: reading line #{}, " - "the block field {} is not " - "valid.\nError message: {}" - "\nNo block will be used.\n" - "".format(self.line_number, r, - detail)) - line_values[9] = 1 - line_values[10] = line_values[1] - line_values[11] = line_values[2] - line_values[1] + sys.stderr.write("Warning: reading line " + f"#{self.line_number}, " + f"the block field {r} is not " + f"valid.\nError message: {detail}" + "\nOne block will be used.\n") + line_values = line_values[:9] + line_values.append(1) + line_values.append([line_values[2] - line_values[1]]) + line_values.append([0]) break else: line_values.append(r) @@ -285,20 +276,18 @@ def get_bed_interval(self, bed_line, is_first_line=False): if is_first_line: sys.stderr.write("Warning: " "The block field 5 (score) is not " - "valid: {}.\nError message: {}" + f"valid: {r}.\nError message: {detail}" "\nOnly the first 4 fields " - "will be used.\n".format(r, - detail)) + "will be used.\n") self.file_type = 'bed6' self.fields_to_read = 4 break else: - sys.stderr.write("Warning: reading line #{}, " + sys.stderr.write("Warning: reading line " + f"#{self.line_number}, " "the block field 5 (score) is not " - "valid: {}.\nError message: {}" - "\n0 will be used.\n" - "".format(self.line_number, r, - detail)) + f"valid: {r}.\nError message: {detail}" + "\n0 will be used.\n") line_values.append(0.) else: line_values.append(tmp) @@ -309,13 +298,13 @@ def get_bed_interval(self, bed_line, is_first_line=False): if self.fields_to_read <= 6: self.file_type = 'bed6' else: - self.file_type = 'bed{}'.format(self.fields_to_read) + self.file_type = f'bed{self.fields_to_read}' return() assert line_values[2] > line_values[1], \ "Start position larger or equal than end" \ - " for line #{}:\n{}\n".format(self.line_number, - bed_line) + f" for line #{self.line_number}:\n{bed_line}\n" + if len(line_values) == 12: check_bed12(line_values, self.line_number, bed_line) @@ -323,9 +312,8 @@ def get_bed_interval(self, bed_line, is_first_line=False): assert len(line_values) > 2, \ "The number of field is less than 3.\n" \ "This is not a bed file.\n" \ - "File: {}\n" \ - "Current line: {}\n".format(self.file_handle.name, - line_values) + f"File: {self.file_handle.name}\n" \ + f"Current line: {line_values}\n" # If there is less than 6 fields, the default values will be added default = [".", 0, "."] line_values = [line_values[i] if i < len(line_values) @@ -340,26 +328,32 @@ def check_bed12(line_values, line_number, bed_line): block_sizes = line_values[10] block_relative_starts = line_values[11] assert len(block_sizes) == block_counts, \ - "The number of blocks: {} does not correspond to" \ - "the number of blocks sizes: {}\nline #{}:\n" \ - "{}".format(block_counts, str(block_sizes), - line_number, bed_line) + f"The number of blocks: {block_counts} does not correspond to" \ + f"the number of blocks sizes: {str(block_sizes)}\nline #{line_number}:" \ + f"\n{bed_line}" assert len(block_relative_starts) == block_counts, \ - "The number of blocks: {} does not correspond to" \ - "the number of blocks relative starts: {}\nline #{}:\n" \ - "{}".format(block_counts, str(block_relative_starts), - line_number, bed_line) + f"The number of blocks: {block_counts} does not correspond to" \ + f"the number of blocks relative starts: {str(block_relative_starts)}" \ + f"\nline #{line_number}:\n{bed_line}" for i in range(block_counts): block_start = line_values[1] + block_relative_starts[i] block_end = block_start + block_sizes[i] assert block_start <= line_values[2], \ - "The block number {} of line {} has a starting position " \ - "greater than the end of the feature:\n{}The" \ + f"The block number {i} of line {line_number} has a starting" \ + f" position greater than the end of the feature:\n{bed_line}The" \ " 12th field of a bed12 should contains relative start" \ - " positions of blocks.".format(i, line_number, bed_line) + " positions of blocks." assert block_end <= line_values[2], \ - "The block number {} of line {} has an ending position " \ - "greater than the end of the feature:\n{}The" \ + f"The block number {i} of line {line_number} has an ending position " \ + f"greater than the end of the feature:\n{bed_line}The" \ " 12th field of a bed12 should contains relative start" \ " positions of blocks and the 11th field should contains" \ - " the length of each block.".format(i, line_number, bed_line) + " the length of each block." + assert min(block_relative_starts) == 0, \ + f"The blocks relative_starts of line\n{bed_line}\n" \ + "does not contain 0. BED blocks must span chromStart" \ + " to chromEnd." + assert max([bstart + bsize for bstart, bsize in zip(block_relative_starts, block_sizes)]) == line_values[2] - line_values[1], \ + f"The blocks described in line\n{bed_line}\n" \ + "does not cover chromEnd. BED blocks must span chromStart" \ + " to chromEnd." diff --git a/pygenometracks/readGtf.py b/pygenometracks/readGtf.py index b76796a9..bbccdd82 100644 --- a/pygenometracks/readGtf.py +++ b/pygenometracks/readGtf.py @@ -81,14 +81,6 @@ def __init__(self, file_path, prefered_name="transcript_name", def __iter__(self): return self - def next(self): - """ - :return: bedInterval object - """ - bed = self.get_bed_interval() - - return bed - def __next__(self): """ :return: bedInterval object diff --git a/pygenometracks/tests/generateAllOutput.sh b/pygenometracks/tests/generateAllOutput.sh index eb3f0080..92350ec5 100644 --- a/pygenometracks/tests/generateAllOutput.sh +++ b/pygenometracks/tests/generateAllOutput.sh @@ -11,36 +11,66 @@ bin/pgt --tracks ./pygenometracks/tests/test_data/bed_tssarrow_tracks.ini --regi bin/pgt --tracks ./pygenometracks/tests/test_data/bed_tssarrow_tracks.ini --region X:3130000-3150000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_bed_tssarrow_zoom2.png bin/pgt --tracks ./pygenometracks/tests/test_data/bed_all_labels_inside.ini --region X:3100000-3200000 --trackLabelFraction 0.2 --width 38 --dpi 130 --trackLabelHAlign right -o ./pygenometracks/tests/test_data/master_bed_all_label_inside.png bin/pgt --tracks ./pygenometracks/tests/test_data/bed_all_labels_inside.ini --region X:3215000-3240000 --trackLabelFraction 0.2 --width 38 --dpi 130 --trackLabelHAlign right --decreasingXAxis -o ./pygenometracks/tests/test_data/master_bed_all_label_inside_dec.png -bin/pgt --tracks pygenometracks/tests/test_data/bed_unusual_formats.ini --region X:20000-40000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_bed_unusual_formats.png bin/pgt --tracks ./pygenometracks/tests/test_data/bed_colormap_genes.ini --region X:3000000-3300000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_bed_colormap_genes.png +bin/pgt --tracks ./pygenometracks/tests/test_data/bed_shuffle.ini --BED ./pygenometracks/tests/test_data/regions_chr1XY.bed --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_bed_shuffle.png +bin/pgt --tracks ./pygenometracks/tests/test_data/bed_vlines.ini --BED ./pygenometracks/tests/test_data/regionsXfakeChr.bed --trackLabelFraction 0.5 --width 38 --dpi 130 --trackLabelHAlign center -o ./pygenometracks/tests/test_data/master_bed_vlines.png + +# non_classical_bed +bin/pgt --tracks pygenometracks/tests/test_data/bed_unusual_formats.ini --region X:20000-40000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_bed_unusual_formats.png +bin/pgt --tracks pygenometracks/tests/test_data/strange_strand.ini --region chr1:0-500 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_strange_strand.png +bin/pgt --tracks pygenometracks/tests/test_data/invalid_rgb.ini --region chr1:0-500 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_invalid_rgb.png +bin/pgt --tracks pygenometracks/tests/test_data/invalid_blockCount.ini --region chrX:15000-24000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_invalid_blockCount.png +bin/pgt --tracks pygenometracks/tests/test_data/invalid_CDScoo.ini --region chrX:15000-24000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_invalid_CDScoo.png +bin/pgt --tracks pygenometracks/tests/test_data/invalid_blocks.ini --region chrX:15000-24000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_invalid_blocks.png +bin/pgt --tracks pygenometracks/tests/test_data/invalid_score.ini --region chrX:15000-24000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_invalid_score.png +bin/pgt --tracks pygenometracks/tests/test_data/bed_different_UTR.ini --region chr1:0-500 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_different_UTR.png # test_bedGraphMatrixTrack: bin/pgt --tracks ./pygenometracks/tests/test_data/bedgraph.ini --region X:2850000-3150000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_bedgraph.png # test bedGraphTrack: -bin/pgt --tracks ./pygenometracks/tests/test_data/bedgraph_useMid.ini --region chr2:73,800,000-75,744,000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_bedgraph_useMid.png -bin/pgt --tracks ./pygenometracks/tests/test_data/bedgraph_useMid.ini --region chr2:74,000,000-74,800,000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_bedgraph_useMid_zoom.png +bin/pgt --tracks ./pygenometracks/tests/test_data/bedgraph_useMid.ini --BED ./pygenometracks/tests/test_data/regions_imbricated_chr2.bed --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_bedgraph_useMid.png bin/pgt --tracks ./pygenometracks/tests/test_data/bedgraph_useMid.ini --region chr2:73,800,000-75,744,000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_bedgraph_useMid.pdf bin/pgt --tracks ./pygenometracks/tests/test_data/operation_bdg.ini --region X:2700000-3100000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_operation_bdg.png +bin/pgt --tracks ./pygenometracks/tests/test_data/bedgraph_withNA.ini --region X:2700000-3100000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_bedgraph_withNA.png +bin/pgt --tracks ./pygenometracks/tests/test_data/bedgraph_negative.ini --region X:2700000-3100000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_negative.png # test bigWigTrack: bin/pgt --tracks ./pygenometracks/tests/test_data/bigwig.ini --region X:2700000-3100000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_bigwig.png bin/pgt --tracks ./pygenometracks/tests/test_data/alpha.ini --region X:2700000-3100000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_alpha.png bin/pgt --tracks ./pygenometracks/tests/test_data/hlines.ini --region X:2700000-3100000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_hlines.png bin/pgt --tracks ./pygenometracks/tests/test_data/operation.ini --region X:2700000-3100000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_operation.png +bin/pgt --tracks ./pygenometracks/tests/test_data/operation.ini --region fakeChr:2700000-3100000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_operation_fakeChr.png +bin/pgt --tracks ./pygenometracks/tests/test_data/grid.ini --region X:2700000-3100000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_grid.png +bin/pgt --tracks ./pygenometracks/tests/test_data/example_bigwig.ini --region X:2,500,000-3,000,000 -o ./pygenometracks/tests/test_data/master_example_bigwig.png +bin/pgt --tracks ./pygenometracks/tests/test_data/example_op.ini --region 2L:0-1000 -o ./pygenometracks/tests/test_data/master_operation_2L.png # test_epilogosTrack: bin/pgt --tracks ./pygenometracks/tests/test_data/epilogos.ini --region X:3100000-3150000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_epilogos.png # test_hiCMatrixTracks: bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic.ini --region X:2500000-3500000 --trackLabelFraction 0.23 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_plot_hic.png -bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_rasterize_height.ini --region X:2500000-2600000 --trackLabelFraction 0.23 --width 38 --dpi 10 -o ./pygenometracks/tests/test_data/master_plot_hic_rasterize_height.pdf +bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_rasterize_height.ini --BED ./pygenometracks/tests/test_data/regions_XY.bed --trackLabelFraction 0.23 --width 38 --dpi 10 -o ./pygenometracks/tests/test_data/master_plot_hic_rasterize_height.pdf bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_log-log.ini --region X:2500000-3500000 --trackLabelFraction 0.23 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_plot_hic_log-log.png bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic.ini --region X:2500000-3500000 --trackLabelFraction 0.23 --width 38 --dpi 130 --decreasingXAxis -o ./pygenometracks/tests/test_data/master_plot_hic_dec.png +bin/pgt --tracks ./pygenometracks/tests/test_data/mcool.ini --region X:2500000-3500000 --trackLabelFraction 0.23 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_mcool.png +bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_small_test.ini --BED ./pygenometracks/tests/test_data/regions_chr1XY.bed --trackLabelFraction 0.23 --width 38 -o ./pygenometracks/tests/test_data/master_plot_hic_small_test.png +bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_small_test.ini --region 1:0-200000 --trackLabelFraction 0.23 --width 38 -o ./pygenometracks/tests/test_data/master_plot_hic_small_test.png +bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_small_test.ini --region chrM:0-20000 --trackLabelFraction 0.23 --width 38 -o ./pygenometracks/tests/test_data/master_plot_hic_small_test_chrM.png +bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_small_test.ini --region chr1:0-5000 --trackLabelFraction 0.23 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_hic_small_test_small_region.png +bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_small_test.ini --region Y:90000000-100000000 --trackLabelFraction 0.23 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_hic_small_test_above_chrY.png +bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_small_test_2.ini --region chr1:0-100000 --trackLabelFraction 0.23 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_hic_small_test_2.png +bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_one_interaction_cool.ini --BED ./pygenometracks/tests/test_data/regions_chr1XY.bed --trackLabelFraction 0.23 --width 38 -o ./pygenometracks/tests/test_data/master_plot_hic_one_interaction_withBED.png +bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_one_interaction_cool.ini --region chrY:0-1000000 --trackLabelFraction 0.23 --width 38 -o ./pygenometracks/tests/test_data/master_plot_hic_one_interaction_withRegion_chrY-0-1000000.png +bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_one_interaction_diag_h5.ini --region chrY:0-1000000 --trackLabelFraction 0.23 --width 38 -o ./pygenometracks/tests/test_data/master_plot_hic_one_interaction_diag_chrY-0-1000000.png +bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks_hic_small_test_3.ini --region chr1:0-200000 --trackLabelFraction 0.23 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_hic_small_test_3.png # test_logScale: bin/pgt --tracks ./pygenometracks/tests/test_data/log1p.ini --region X:2700000-3100000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_log1p.png bin/pgt --tracks ./pygenometracks/tests/test_data/log.ini --region chr2:73,800,000-75,744,000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_log.png +bin/pgt --tracks ./pygenometracks/tests/test_data/log_grid.ini --region chr2:73,800,000-75,744,000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_log_grid.png +bin/pgt --tracks ./pygenometracks/tests/test_data/log1p_grid.ini --region X:2700000-3100000 --trackLabelFraction 0.2 --dpi 130 -o ./pygenometracks/tests/test_data/master_log1p_grid.png +bin/pgt --tracks ./pygenometracks/tests/test_data/log_more.ini --region chr2:73,800,000-75,744,000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_log_more.png # test_make_tracks: bin/make_tracks_file --trackFiles pygenometracks/tests/test_data/Li_et_al_2015.h5 pygenometracks/tests/test_data/bigwig_chrx_2e6_5e6.bw pygenometracks/tests/test_data/tad_classification.bed pygenometracks/tests/test_data/epilog.qcat.bgz -o pygenometracks/tests/test_data/master_tracks.ini @@ -55,6 +85,8 @@ bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks.ini --region Y: bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks.ini --region X:0-1000000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_plot_2.png bin/pgt --tracks ./pygenometracks/tests/test_data/empty.ini --region X:3000000-3500000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_empty.png bin/pgt --tracks ./pygenometracks/tests/test_data/browser_tracks.ini --region X:3000000-3500000 --trackLabelFraction 0.2 --width 38 --dpi 130 --decreasingXAxis -o ./pygenometracks/tests/test_data/master_plot_dec.png +bin/pgt --tracks ./pygenometracks/tests/test_data/firstTrackOverlay.ini --region X:3000000-3500000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_empty2.png + # test_tracks_label: bin/pgt --tracks ./pygenometracks/tests/test_data/title.ini --region X:3000000-3500000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_title_0.2.png @@ -63,9 +95,12 @@ bin/pgt --tracks ./pygenometracks/tests/test_data/title.ini --region X:3000000-3 bin/pgt --tracks ./pygenometracks/tests/test_data/title.ini --region X:3000000-3500000 --trackLabelFraction 0.5 --trackLabelHAlign right --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_title_0.5_ral.png bin/pgt --tracks ./pygenometracks/tests/test_data/title.ini --region X:3000000-3500000 --trackLabelFraction 0.5 --trackLabelHAlign center --width 38 --dpi 130 -o ./pygenometracks/tests/test_data/master_title_0.5_cal.png bin/pgt --tracks ./pygenometracks/tests/test_data/title.ini --region X:3000000-3500000 --trackLabelFraction 0.5 --trackLabelHAlign center --width 38 --dpi 250 -o ./pygenometracks/tests/test_data/master_title_0.5_cal_d250.png +bin/pgt --tracks ./pygenometracks/tests/test_data/title.ini --region X:3000000-3500000 --height 10 --title force_height -o ./pygenometracks/tests/test_data/master_title_force_height.png # tests arcs bin/pgt --tracks ./pygenometracks/tests/test_data/short_long_arcs.ini --region chr11:40000000-46000000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_short_long_arcs.png +bin/pgt --tracks ./pygenometracks/tests/test_data/arcs_use_middle.ini --region X:3000000-3300000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_arcs_use_middle.png +bin/pgt --tracks ./pygenometracks/tests/test_data/arcs_no_score.ini --region X:3000000-3300000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_arcs_no_score.png # tests scaleBar bin/pgt --tracks pygenometracks/tests/test_data/scale_bar.ini --region X:3200000-3300000 --trackLabelFraction 0.2 --width 38 --dpi 130 -o pygenometracks/tests/test_data/master_scale_bar_zoom.png diff --git a/pygenometracks/tests/test_arcs.py b/pygenometracks/tests/test_arcs.py index 0c7f6424..d12bc965 100644 --- a/pygenometracks/tests/test_arcs.py +++ b/pygenometracks/tests/test_arcs.py @@ -4,6 +4,7 @@ from tempfile import NamedTemporaryFile import os.path import pygenometracks.plotTracks +from pygenometracks.utilities import InputError mpl.use('agg') ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), @@ -99,21 +100,238 @@ with open(os.path.join(ROOT, "short_long_arcs.ini"), 'w') as fh: fh.write(browser_tracks) +with open(os.path.join(ROOT, "short_long_arcs_incorrect.ini"), 'w') as fh: + fh.write(browser_tracks.replace('compact_arcs_level = 2', 'compact_arcs_level = 2\nylim=1000000')) + +browser_tracks = """ +[x-axis] +where = top + +[spacer] +height = 0.05 +[hic matrix] +file = Li_et_al_2015.cool +title = depth = 300000; transform = log1p; min_value = 5 (next track: overlay_previous = share-y links_type = loops) +depth = 300000 +min_value = 5 +transform = log1p +file_type = hic_matrix +show_masked_bins = false + +[test arcs overlay] +file = test_wide.arcs +color = red +line_width = 5 +links_type = loops +overlay_previous = share-y + +[test arcs] +file = test_wide.arcs +line_width = 3 +color = RdYlGn +title = links line_width = 3 color RdYlGn +height = 3 +orientation = inverted + +[spacer] +height = 1 + +[hic matrix] +file = Li_et_al_2015.cool +title = depth = 300000; transform = log1p; min_value = 5 (next track: overlay_previous = share-y links_type = loops) +depth = 300000 +min_value = 5 +transform = log1p +file_type = hic_matrix +show_masked_bins = false + +[test arcs overlay] +file = test_wide.arcs +color = red +line_width = 5 +links_type = loops +overlay_previous = share-y + +[test arcs] +file = test_wide.arcs +line_width = 3 +color = RdYlGn +title = links line_width = 3 color RdYlGn use_middle = true +use_middle = true +height = 3 +orientation = inverted +""" +with open(os.path.join(ROOT, "arcs_use_middle.ini"), 'w') as fh: + fh.write(browser_tracks) + + +browser_tracks = """ +[arcs] +title = loop with scores +file = test_high_score.arcs +color = cividis +height = 2 +links_type = loops + +[arcs] +title = arcs with scores +file = test_high_score.arcs +color = cividis +height = 2 +min_value = 0 +max_value = 80 + +[arcs] +title = arcs without scores +file = test_noscore.arcs +color = blue +line_width = 0.5 +height = 2 + +""" +with open(os.path.join(ROOT, "arcs_no_score.ini"), 'w') as fh: + fh.write(browser_tracks) + + +browser_tracks = """ +[arcs] +title = loop with scores +file = test_high_score.arcs +color = cividis +height = 2 +links_type = loops + +[arcs] +title = arcs with scores +file = test_high_score.arcs +color = cividis +height = 2 +min_value = 0 +max_value = 80 + +[arcs] +title = arcs without scores +file = test_noscore.arcs +color = cividis +height = 2 + +""" +with open(os.path.join(ROOT, "arcs_no_score_incorrect.ini"), 'w') as fh: + fh.write(browser_tracks) + +with open(os.path.join(ROOT, "arcs_no_score_invalid_score.ini"), 'w') as fh: + fh.write(browser_tracks.replace('test_noscore.arcs', + 'arcs_invalid_score.arcs')) + +with open(os.path.join(ROOT, "arcs_no_score_invalid_score2.ini"), 'w') as fh: + fh.write(browser_tracks.replace('test_noscore.arcs', + 'arcs_invalid_score2.arcs')) + +for suf in ['', '2']: + browser_tracks = f""" +[arcs] +file = arcs_invalid{suf}.arcs +""" + with open(os.path.join(ROOT, f"arcs_invalid{suf}.ini"), 'w') as fh: + fh.write(browser_tracks) tolerance = 13 # default matplotlib pixed difference tolerance def test_short_long_arcs(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region chr11:40000000-46000000 --trackLabelFraction 0.2" \ - " --width 38 --dpi 130 --outFileName {1}" \ - "".format(os.path.join(ROOT, "short_long_arcs.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + for suf in ['', '_incorrect']: + ini_file = os.path.join(ROOT, f"short_long_arcs{suf}.ini") + region = "chr11:40000000-46000000" + expected_file = os.path.join(ROOT, 'master_short_long_arcs.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + # Remove incorrect ini file + if 'incorrect' in ini_file: + os.remove(ini_file) + + +def test_use_middle_arcs(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "arcs_use_middle.ini") + region = "X:3000000-3300000" + expected_file = os.path.join(ROOT, 'master_arcs_use_middle.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_short_long_arcs.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res os.remove(outfile.name) + + +def test_arcs_no_score(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + for suf in ['', '_incorrect', '_invalid_score', '_invalid_score2']: + ini_file = os.path.join(ROOT, f"arcs_no_score{suf}.ini") + region = "X:3000000-3300000" + expected_file = os.path.join(ROOT, 'master_arcs_no_score.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + # Remove the incorrect ini files or using invalid files + if 'incorrect' in ini_file or 'invalid' in ini_file: + os.remove(ini_file) + + +def test_arcs_invalid(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=True) + ini_file = os.path.join(ROOT, "arcs_invalid.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + try: + pygenometracks.plotTracks.main(args) + except InputError as e: + assert 'not enough values to unpack (expected 6, got 5)' in str(e) + else: + raise Exception("The arcs_invalid should fail.") + os.remove(ini_file) + + +def test_arcs_invalid2(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=True) + ini_file = os.path.join(ROOT, "arcs_invalid2.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + try: + pygenometracks.plotTracks.main(args) + except InputError as e: + assert 'One of the fields is not an integer.' in str(e) + else: + raise Exception("The arcs_invalid2 should fail.") + os.remove(ini_file) diff --git a/pygenometracks/tests/test_bedGraphMatrixTrack.py b/pygenometracks/tests/test_bedGraphMatrixTrack.py index 16560739..76d10be0 100644 --- a/pygenometracks/tests/test_bedGraphMatrixTrack.py +++ b/pygenometracks/tests/test_bedGraphMatrixTrack.py @@ -129,15 +129,16 @@ def test_bedgraphmatrix_track(): + outfile = NamedTemporaryFile(suffix='.png', prefix='bedgraph_test_', + delete=False) + ini_file = os.path.join(ROOT, "bedgraph.ini") region = "X:2850000-3150000" - outfile = NamedTemporaryFile(suffix='.png', prefix='bedgraph_test_', delete=False) - args = "--tracks {ini} --region {region} --trackLabelFraction 0.2 " \ - "--dpi 130 --outFileName {outfile}" \ - "".format(ini=os.path.join(ROOT, "bedgraph.ini"), - outfile=outfile.name, region=region).split() + expected_file = os.path.join(ROOT, 'master_bedgraph.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_bedgraph.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res diff --git a/pygenometracks/tests/test_bedGraphTrack.py b/pygenometracks/tests/test_bedGraphTrack.py index ba8389ca..29c986c7 100644 --- a/pygenometracks/tests/test_bedGraphTrack.py +++ b/pygenometracks/tests/test_bedGraphTrack.py @@ -3,8 +3,9 @@ mpl.use('agg') from matplotlib.testing.compare import compare_images from tempfile import NamedTemporaryFile -import os.path +import os import pygenometracks.plotTracks +from pygenometracks.utilities import InputError ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_data") @@ -48,6 +49,37 @@ with open(os.path.join(ROOT, "bedgraph_useMid.ini"), 'w') as fh: fh.write(browser_tracks) +browser_tracks = """ +[x-axis] +where = top + +[test bedgraph neg] +file = test_with_neg_values.bg.gz +color = blue +negative_color = red +title = color = blue; negative_color = red +height = 5 + +[test bedgraph neg] +file = test_with_neg_values.bg.gz +color = cyan +negative_color = darkred +type = line:2 +title = color = cyan; negative_color = darkred; type = line:2 +height = 5 + +[test bedgraph neg] +file = test_with_neg_values.bg.gz +color = black +negative_color = lime +type = points:2 +title = color = black; negative_color = lime; type = points:2 +height = 5 +""" + +with open(os.path.join(ROOT, "bedgraph_negative.ini"), 'w') as fh: + fh.write(browser_tracks) + browser_tracks = """ [test file] file = bedgraph_chrx_2e6_5e6.bg.bgz @@ -98,7 +130,7 @@ [test op2] file = bedgraph2_X_2.5e6_3.5e6.bdg -second_file = bedgraph_chrx_2e6_5e6.bg.bgz +second_file = bedgraph_chrx_2e6_5e6_2.bg.bgz color = red negative_color = blue height = 8 @@ -129,73 +161,261 @@ """ with open(os.path.join(ROOT, "operation_bdg.ini"), 'w') as fh: fh.write(browser_tracks) +with open(os.path.join(ROOT, "incorrect_operation_bdg.ini"), 'w') as fh: + fh.write(browser_tracks.replace('operation = log1p(file)\n', 'operation = log1p(file)\ny_axis_values = original\n')) + +bedgraph_withNA = """ +[test bedgraph withNA] +file = bedgraph_withNA.bdg +height = 3 + +[x-axis] +""" +with open(os.path.join(ROOT, "bedgraph_withNA.ini"), 'w') as fh: + fh.write(bedgraph_withNA) + +for suff in ["", "2", "3"]: + invalid_bedgraph = f""" +[invalid_bedgraph{suff}] +file = invalid_bedgraph{suff}.bdg +height = 3 + +[x-axis] +""" + with open(os.path.join(ROOT, f"invalid_bedgraph{suff}.ini"), 'w') as fh: + fh.write(invalid_bedgraph) +unsorted_bedgraph = """ +[unsorted_bedgraph] +file = unsorted_bedgraph.bdg +height = 3 + +[x-axis] +""" +with open(os.path.join(ROOT, "unsorted_bedgraph.ini"), 'w') as fh: + fh.write(unsorted_bedgraph) + +# Write a bedgraph with negative values: +with open(os.path.join(ROOT, "bedgraph_chrx_2e6_5e6.bg"), 'r') as f: + with open(os.path.join(ROOT, "bedgraph_chrx_2e6_5e6_m.bg"), 'w') as fo: + for line in f: + ls = line.split('\t') + ls[3] = '-' + ls[3] + fo.write('\t'.join(ls)) + +log1p_with_neg = """ +[m_bedgraph] +file = bedgraph_chrx_2e6_5e6_m.bg +transform = log1p +height = 3 + +[x-axis] +""" +with open(os.path.join(ROOT, "log1pm_bedgraph.ini"), 'w') as fh: + fh.write(log1p_with_neg) tolerance = 13 # default matplotlib pixed difference tolerance -def test_plot_bedgraph_tracks(): +def test_plot_bedgraph_tracks_with_bed(): + extension = '.png' - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region chr2:73,800,000-75,744,000 "\ - "--trackLabelFraction 0.2 --width 38 --dpi 130 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "bedgraph_useMid.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix=extension, prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "bedgraph_useMid.ini") + bed_file = os.path.join(ROOT, 'regions_imbricated_chr2.bed') + args = f"--tracks {ini_file} --BED {bed_file} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_bedgraph_useMid.png'), + for region in ['chr2:73800000-75744000', 'chr2:74000000-74800000']: + region_str = region.replace(':', '-') + output_file = outfile.name[:-4] + '_' + region_str + extension + expected_file = os.path.join(ROOT, 'master_bedgraph_useMid_' + + region_str + extension) + res = compare_images(expected_file, + output_file, tolerance) + assert res is None, res + + os.remove(output_file) + + +def test_plot_bedgraph_tracks_individual(): + extension = '.png' + + for region in ['chr2:73800000-75744000', 'chr2:74000000-74800000']: + outfile = NamedTemporaryFile(suffix=extension, prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "bedgraph_useMid.ini") + region_str = region.replace(':', '-') + expected_file = os.path.join(ROOT, 'master_bedgraph_useMid_' + + region_str + extension) + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_bedgraph_tracks_rasterize(): + + outfile = NamedTemporaryFile(suffix='.pdf', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "bedgraph_useMid.ini") + region = "chr2:73,800,000-75,744,000" + expected_file = os.path.join(ROOT, 'master_bedgraph_useMid.pdf') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res os.remove(outfile.name) + os.remove(expected_file.replace('.pdf', '_pdf.png')) -def test_plot_bedgraph_tracks_zoom(): - - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region chr2:74,000,000-74,800,000 "\ - "--trackLabelFraction 0.2 --width 38 --dpi 130 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "bedgraph_useMid.ini"), - outfile.name).split() +def test_op_bdg(): + outfile = NamedTemporaryFile(suffix='.png', prefix='bdg_op_test_', + delete=False) + for pref in ['', 'incorrect_']: + ini_file = os.path.join(ROOT, f"{pref}operation_bdg.ini") + region = "X:2700000-3100000" + expected_file = os.path.join(ROOT, 'master_operation_bdg.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + if 'incorrect' in ini_file: + os.remove(ini_file) + + +def test_bdg_withNA(): + outfile = NamedTemporaryFile(suffix='.png', prefix='bdg_NA_', delete=False) + ini_file = os.path.join(ROOT, "bedgraph_withNA.ini") + region = "X:2700000-3100000" + expected_file = os.path.join(ROOT, 'master_bedgraph_withNA.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_bedgraph_useMid_zoom.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res os.remove(outfile.name) -def test_plot_bedgraph_tracks_rasterize(): - - outfile = NamedTemporaryFile(suffix='.pdf', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region chr2:73,800,000-75,744,000 "\ - "--trackLabelFraction 0.2 --width 38 --dpi 130 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, 'bedgraph_useMid.ini'), - outfile.name).split() +def test_bdg_unsorted(): + outfile = NamedTemporaryFile(suffix='.png', prefix='pgt_test_', delete=False) + ini_file = os.path.join(ROOT, "unsorted_bedgraph.ini") + region = "X:2700000-3100000" + expected_file = os.path.join(ROOT, 'master_bedgraph_withNA.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_bedgraph_useMid.pdf'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res os.remove(outfile.name) -def test_op_bdg(): +def test_negative(): region = "X:2700000-3100000" - outfile = NamedTemporaryFile(suffix='.png', prefix='bdg_op_test_', delete=False) + outfile = NamedTemporaryFile(suffix='.png', prefix='bedgraph_negative_test_', delete=False) args = "--tracks {ini} --region {region} --trackLabelFraction 0.2 " \ "--dpi 130 --outFileName {outfile}" \ - "".format(ini=os.path.join(ROOT, "operation_bdg.ini"), + "".format(ini=os.path.join(ROOT, "bedgraph_negative.ini"), outfile=outfile.name, region=region).split() pygenometracks.plotTracks.main(args) print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_operation_bdg.png'), + res = compare_images(os.path.join(ROOT, 'master_negative.png'), outfile.name, tolerance) assert res is None, res os.remove(outfile.name) + + +def test_invalid_bedgraph(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pgt_test_', delete=True) + ini_file = os.path.join(ROOT, "invalid_bedgraph.ini") + region = "X:2700000-3100000" + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + try: + pygenometracks.plotTracks.main(args) + except InputError as e: + assert 'not enough values to unpack (expected 3, got 1)' in str(e) + else: + raise Exception("The invalid_bedgraph should fail.") + + os.remove(ini_file) + + +def test_invalid_bedgraph2(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pgt_test_', delete=True) + ini_file = os.path.join(ROOT, "invalid_bedgraph2.ini") + region = "X:2700000-3100000" + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + try: + pygenometracks.plotTracks.main(args) + except InputError as e: + assert 'The start field is not an integer.' in str(e) + else: + raise Exception("The invalid_bedgraph2 should fail.") + + os.remove(ini_file) + + +def test_invalid_bedgraph3(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pgt_test_', delete=True) + ini_file = os.path.join(ROOT, "invalid_bedgraph3.ini") + region = "X:2700000-3100000" + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + try: + pygenometracks.plotTracks.main(args) + except InputError as e: + assert 'The end field is not an integer.' in str(e) + else: + raise Exception("The invalid_bedgraph3 should fail.") + + os.remove(ini_file) + + +def test_bedgraph_neg_log1p(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pgt_test_', delete=True) + ini_file = os.path.join(ROOT, "log1pm_bedgraph.ini") + region = "X:2700000-3100000" + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + try: + pygenometracks.plotTracks.main(args) + except Exception as e: + assert 'coverage contains values below or equal to - 1' in str(e) + else: + raise Exception("The bedgraph_neg_log1p should fail.") + + os.remove(ini_file) + os.remove(os.path.join(ROOT, "bedgraph_chrx_2e6_5e6_m.bg")) diff --git a/pygenometracks/tests/test_bed_and_gtf_tracks.py b/pygenometracks/tests/test_bed_and_gtf_tracks.py index 7194a0b9..bc5ca7a1 100644 --- a/pygenometracks/tests/test_bed_and_gtf_tracks.py +++ b/pygenometracks/tests/test_bed_and_gtf_tracks.py @@ -461,50 +461,30 @@ with open(os.path.join(ROOT, "bed_genes_rgb.ini"), 'w') as fh: fh.write(browser_tracks) -browser_tracks = """ -[macs2 broadPeak] -file = broadPeak.broadPeak -title = broadPeak -file_type = bed - -[spacer] - -[macs2 gappedPeak] -file = gappedPeak.gappedPeak -title = gappedPeak -file_type = bed - -[spacer] - -[macs2 filteredbed] -file = filtered.results.bed -title = filtered.results.bed (strange format) -file_type = bed -""" -with open(os.path.join(ROOT, "bed_unusual_formats.ini"), 'w') as fh: - fh.write(browser_tracks) +with open(os.path.join(ROOT, "bed_genes_rgb_incorrect.ini"), 'w') as fh: + fh.write(browser_tracks.replace('style = flybase', 'style = inexisting')) wrong_track = """ [test gtf] -file = ../dm3_subset_BDGP5.78_gtf.dat +file = dm3_subset_BDGP5.78_gtf.dat height = 10 title = gtf from ensembl (with dat extension) fontsize = 12 file_type = bed """ -with open(os.path.join(ROOT, "uncorrect_ini_files", "gtf_as_bed.ini"), 'w') as fh: +with open(os.path.join(ROOT, "gtf_as_bed.ini"), 'w') as fh: fh.write(wrong_track) wrong_track = """ [test bed] -file = ../dm3_genes.bed.gz +file = dm3_genes.bed.gz height = 10 title = bed file fontsize = 12 file_type = gtf """ -with open(os.path.join(ROOT, "uncorrect_ini_files", "bed_as_gtf.ini"), 'w') as fh: +with open(os.path.join(ROOT, "bed_as_gtf.ini"), 'w') as fh: fh.write(wrong_track) browser_tracks = """ @@ -541,14 +521,98 @@ [scores in cod+utr 2] file = dm3_genes_withrgbandscore.bed.gz -title = genes with scores both in coding and utr as Reds +title = genes with scores both in coding and utr as Reds min_value = 0.2 max_value = 2 color = Reds color_utr = Reds height = 10.0 +min_value = 0.2 +max_value = 2 """ with open(os.path.join(ROOT, "bed_colormap_genes.ini"), 'w') as fh: fh.write(browser_tracks) +browser_tracks = """ +[genes] +file = dm3_genes_withrgbandscore.bed.gz +title = bed color = Reds +color = Reds +height = 4 + +[spacer] + +[genes] +file = dm3_genes_withrgbandscore_shuffled.bed.gz +title = bed color = Reds bed is not sorted +color = Reds +height = 4 + +[spacer] + +[genes] +file = dm3_genes_withrgbandscore_shuffled.bed.gz +title = bed color = Reds global_max_row = true and bed is not sorted +color = Reds +global_max_row = true +height = 4 + +[x-axis] +""" +with open(os.path.join(ROOT, "bed_shuffle.ini"), 'w') as fh: + fh.write(browser_tracks) + +browser_tracks = """ +[genes] +file = dm3_genes_withrgbandscore.bed.gz +title = bed global_max_row = true labels = false +labels = false +global_max_row = true +height = 4 + +[spacer] + +[x-axis] +title = centered title + +[vlines] +file = tad_classification.bed +type = vlines +line_width = 3 +""" +with open(os.path.join(ROOT, "bed_vlines.ini"), 'w') as fh: + fh.write(browser_tracks) +with open(os.path.join(ROOT, "bed_vlines_incorrect.ini"), 'w') as fh: + fh.write(browser_tracks + 'line_style = dashed\n') + +browser_tracks = """ +[genes1] +file = example.bed +title = bed style = flybase +style = flybase +height = 4 + +[spacer] + +[genes2] +file = example.bed +title = bed style = UCSC +style = UCSC +height = 4 + +[spacer] + +[genes1] +file = example.bed +title = bed style = tssarrow +style = tssarrow +height = 4 + +[spacer] + +[x-axis] +""" +with open(os.path.join(ROOT, "bed_different_UTR.ini"), 'w') as fh: + fh.write(browser_tracks) + tolerance = 13 # default matplotlib pixed difference tolerance @@ -556,13 +620,14 @@ def test_plot_tracks_bed_and_gtf(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3300000 "\ + ini_file = os.path.join(ROOT, 'bed_and_gtf_tracks.ini') + region = "X:3000000-3300000" + expected_file = os.path.join(ROOT, 'master_bed_and_gtf.png') + args = f"--tracks {ini_file} --region {region} "\ "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, 'bed_and_gtf_tracks.ini'), - outfile.name).split() + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_bed_and_gtf.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -573,13 +638,14 @@ def test_plot_tracks_bed_arrow(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3120000-3150000 "\ + ini_file = os.path.join(ROOT, 'bed_arrow_tracks.ini') + region = "X:3120000-3150000" + expected_file = os.path.join(ROOT, 'master_bed_arrow.png') + args = f"--tracks {ini_file} --region {region} "\ "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, 'bed_arrow_tracks.ini'), - outfile.name).split() + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_bed_arrow.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -590,13 +656,15 @@ def test_plot_tracks_bed_arrow_zoom(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3130000-3140000 "\ + + ini_file = os.path.join(ROOT, "bed_arrow_tracks.ini") + region = "X:3130000-3140000" + expected_file = os.path.join(ROOT, 'master_bed_arrow_zoom.png') + args = f"--tracks {ini_file} --region {region} "\ "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, 'bed_arrow_tracks.ini'), - outfile.name).split() + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_bed_arrow_zoom.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -607,13 +675,15 @@ def test_plot_tracks_flybase(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3300000 "\ + + ini_file = os.path.join(ROOT, "bed_flybase_tracks.ini") + region = "X:3000000-3300000" + expected_file = os.path.join(ROOT, 'master_bed_flybase.png') + args = f"--tracks {ini_file} --region {region} "\ "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, 'bed_flybase_tracks.ini'), - outfile.name).split() + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_bed_flybase.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -624,13 +694,14 @@ def test_plot_tracks_tssarrow(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3300000 "\ + ini_file = os.path.join(ROOT, "bed_tssarrow_tracks.ini") + region = "X:3000000-3300000" + expected_file = os.path.join(ROOT, 'master_bed_tssarrow.png') + args = f"--tracks {ini_file} --region {region} "\ "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, 'bed_tssarrow_tracks.ini'), - outfile.name).split() + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_bed_tssarrow.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -641,13 +712,14 @@ def test_plot_tracks_tssarrow_zoom(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3020000-3070000 "\ + ini_file = os.path.join(ROOT, "bed_tssarrow_tracks.ini") + region = "X:3020000-3070000" + expected_file = os.path.join(ROOT, 'master_bed_tssarrow_zoom.png') + args = f"--tracks {ini_file} --region {region} "\ "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, 'bed_tssarrow_tracks.ini'), - outfile.name).split() + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_bed_tssarrow_zoom.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -658,13 +730,14 @@ def test_plot_tracks_tssarrow_zoom2(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3130000-3150000 "\ + ini_file = os.path.join(ROOT, "bed_tssarrow_tracks.ini") + region = "X:3130000-3150000" + expected_file = os.path.join(ROOT, 'master_bed_tssarrow_zoom2.png') + args = f"--tracks {ini_file} --region {region} "\ "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, 'bed_tssarrow_tracks.ini'), - outfile.name).split() + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_bed_tssarrow_zoom2.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -675,13 +748,14 @@ def test_plot_tracks_bed_with_maxLab(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:2000000-3500000 "\ - "--trackLabelFraction 0.2 --width 38 --dpi 130 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, 'bed_maxLab_tracks.ini'), - outfile.name).split() + ini_file = os.path.join(ROOT, "bed_maxLab_tracks.ini") + region = "X:2000000-3500000" + expected_file = os.path.join(ROOT, 'master_maxLab.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_maxLab.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -692,30 +766,37 @@ def test_plot_tracks_genes_rgb(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region chr2:74,650,000-74,710,000 "\ - "--trackLabelFraction 0.2 --width 38 --dpi 130 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, 'bed_genes_rgb.ini'), - outfile.name).split() - pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_bed_genes_rgb.png'), - outfile.name, tolerance) - assert res is None, res + for suf in ['', '_incorrect']: + ini_file = os.path.join(ROOT, f"bed_genes_rgb{suf}.ini") + region = "chr2:74,650,000-74,710,000" + expected_file = os.path.join(ROOT, 'master_bed_genes_rgb.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res - os.remove(outfile.name) + os.remove(outfile.name) + # remove the incorrect ini file + if 'incorrect' in ini_file: + os.remove(ini_file) def test_plot_tracks_bed_all_label_inside(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3100000-3200000 "\ - "--trackLabelFraction 0.2 --width 38 --dpi 130 " \ - "--trackLabelHAlign right --outFileName {1}" \ - "".format(os.path.join(ROOT, 'bed_all_labels_inside.ini'), - outfile.name).split() + ini_file = os.path.join(ROOT, "bed_all_labels_inside.ini") + region = "X:3100000-3200000" + expected_file = os.path.join(ROOT, 'master_bed_all_label_inside.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + "--trackLabelHAlign right "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_bed_all_label_inside.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -726,80 +807,136 @@ def test_plot_tracks_bed_all_label_inside_Xdec(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3215000-3240000 "\ - "--trackLabelFraction 0.2 --width 38 --dpi 130 " \ - "--trackLabelHAlign right --outFileName {1} --decreasingXAxis" \ - "".format(os.path.join(ROOT, 'bed_all_labels_inside.ini'), - outfile.name).split() + ini_file = os.path.join(ROOT, "bed_all_labels_inside.ini") + region = "X:3215000-3240000" + expected_file = os.path.join(ROOT, 'master_bed_all_label_inside_dec.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + "--trackLabelHAlign right --decreasingXAxis "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_bed_all_label_inside_dec.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res os.remove(outfile.name) -def test_plot_tracks_bed_unusual_format(): - - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', - delete=False) - args = "--tracks {0} --region X:20000-40000 "\ - "--trackLabelFraction 0.2 --width 38 --dpi 130 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, 'bed_unusual_formats.ini'), - outfile.name).split() - pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_bed_unusual_formats.png'), - outfile.name, tolerance) - assert res is None, res - os.remove(outfile.name) - - def test_gtf_as_bed(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3100000-3200000 "\ - "--trackLabelFraction 0.2 --width 38 --dpi 130 " \ - "--trackLabelHAlign right --outFileName {1}" \ - "".format(os.path.join(ROOT, "uncorrect_ini_files", "gtf_as_bed.ini"), - outfile.name).split() + ini_file = os.path.join(ROOT, "gtf_as_bed.ini") + region = "X:3100000-3200000" + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() try: pygenometracks.plotTracks.main(args) except InputError as e: assert 'This is probably not a bed file.' in str(e) else: raise Exception("The gtf as bed should fail.") + os.remove(ini_file) def test_bed_as_gtf(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3100000-3200000 "\ - "--trackLabelFraction 0.2 --width 38 --dpi 130 " \ - "--trackLabelHAlign right --outFileName {1}" \ - "".format(os.path.join(ROOT, "uncorrect_ini_files", "bed_as_gtf.ini"), - outfile.name).split() + ini_file = os.path.join(ROOT, "bed_as_gtf.ini") + region = "X:3100000-3200000" + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() try: pygenometracks.plotTracks.main(args) except InputError as e: assert 'This is not a gtf file.' in str(e) else: raise Exception("The bed as gtf should fail.") + os.remove(ini_file) def test_plot_tracks_bed_scores(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3300000 "\ + ini_file = os.path.join(ROOT, "bed_colormap_genes.ini") + region = "X:3000000-3300000" + expected_file = os.path.join(ROOT, 'master_bed_colormap_genes.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_bed_shuffle(): + extension = '.png' + + outfile = NamedTemporaryFile(suffix=extension, prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "bed_shuffle.ini") + bed_file = os.path.join(ROOT, 'regions_chr1XY.bed') + args = f"--tracks {ini_file} --BED {bed_file} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + for region in ['chr1:0-500000', 'chrX:2500000-2600000', 'chrY:0-1000000']: + region_str = region.replace(':', '-') + output_file = outfile.name[:-4] + '_' + region_str + extension + expected_file = os.path.join(ROOT, 'master_bed_shuffle_' + + region_str + extension) + res = compare_images(expected_file, + output_file, tolerance) + assert res is None, res + + os.remove(output_file) + + +def test_plot_tracks_bed_vlines(): + extension = '.png' + outfile = NamedTemporaryFile(suffix=extension, prefix='pyGenomeTracks_test_', + delete=False) + bed_file = os.path.join(ROOT, 'regionsXfakeChr.bed') + for suf in ['', '_incorrect']: + ini_file = os.path.join(ROOT, f"bed_vlines{suf}.ini") + args = f"--tracks {ini_file} --BED {bed_file} "\ + "--trackLabelFraction 0.5 --width 38 --dpi 130 "\ + "--trackLabelHAlign center "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + for region in ['X:3000000-3300000', 'fakeChr:0-100']: + region_str = region.replace(':', '-') + output_file = outfile.name[:-4] + '_' + region_str + extension + expected_file = os.path.join(ROOT, 'master_bed_vlines_' + + region_str + extension) + res = compare_images(expected_file, + output_file, tolerance) + assert res is None, res + + os.remove(output_file) + if 'incorrect' in ini_file: + os.remove(ini_file) + + +def test_plot_tracks_bed_different_UTR(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "bed_different_UTR.ini") + region = "chr1:0-500" + expected_file = os.path.join(ROOT, 'master_different_UTR.png') + args = f"--tracks {ini_file} --region {region} "\ "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, 'bed_colormap_genes.ini'), - outfile.name).split() + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_bed_colormap_genes.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res diff --git a/pygenometracks/tests/test_bigWigTrack.py b/pygenometracks/tests/test_bigWigTrack.py index 012afb0f..50d8d0d5 100644 --- a/pygenometracks/tests/test_bigWigTrack.py +++ b/pygenometracks/tests/test_bigWigTrack.py @@ -26,6 +26,8 @@ height = 2 type = line:0.2 title = type = line:0.2 +min_value = auto +max_value = auto [spacer] @@ -241,6 +243,9 @@ with open(os.path.join(ROOT, "operation.ini"), 'w') as fh: fh.write(tracks) +with open(os.path.join(ROOT, "incorrect_operation.ini"), 'w') as fh: + fh.write(tracks.replace('operation = min(file, second_file)\n', 'operation = min(file, second_file)\ny_axis_values = original\n')) + tracks = """ [test bigwig] file = bigwig2_X_2.5e6_3.5e6.bw @@ -332,19 +337,112 @@ with open(os.path.join(ROOT, "alpha.ini"), 'w') as fh: fh.write(tracks) +tracks = """ +[test bigwig fill] +file = bigwig2_X_2.5e6_3.5e6.bw +color = black +height = 2 +type = fill +title = bigwig: black fill (height = 2) + +[test bigwig fill with grid] +file = bigwig2_X_2.5e6_3.5e6.bw +color = black +height = 2 +type = fill +grid = true +title = bigwig: black fill with grid (height = 2) + +[spacer] + +[test bigwig fill with grid] +file = bigwig2_X_2.5e6_3.5e6.bw +color = black +height = 5 +type = fill +grid = true +title = bigwig: black fill with grid (height = 5) + +[spacer] + +[test bigwig fill with grid] +file = bigwig2_X_2.5e6_3.5e6.bw +color = black +height = 5 +type = fill +grid = true +max_value = 50 +title = bigwig: black fill with grid (height = 5 max_value = 50) + +[spacer] + +[test bigwig fill with grid] +file = bigwig2_X_2.5e6_3.5e6.bw +color = black +height = 15 +type = fill +grid = true +max_value = 50 +title = bigwig: black fill with grid (height = 15 max_value = 50) + +[x-axis] +""" + +with open(os.path.join(ROOT, "grid.ini"), 'w') as fh: + fh.write(tracks) + +tracks = """ +[bigwig file test] +file = bigwig_chrx_2e6_5e6.bw +# height of the track in cm (optional value) +height = 4 +title = bigwig +min_value = 0 +max_value = 30 +""" + +with open(os.path.join(ROOT, "example_bigwig.ini"), 'w') as fh: + fh.write(tracks) + +with open(os.path.join(ROOT, "example_bigwig_invalid_custom_color.ini"), 'w') as fh: + fh.write(tracks + 'color = (a') + +with open(os.path.join(ROOT, "example_bigwig_invalid_custom_color2.ini"), 'w') as fh: + fh.write(tracks + 'color = (1)') + +with open(os.path.join(ROOT, "example_bigwig_invalid_custom_color3.ini"), 'w') as fh: + fh.write(tracks + 'color = Reds') + +with open(os.path.join(ROOT, "example_bigwig_invalid_transform.ini"), 'w') as fh: + fh.write(tracks + 'transform = myfunction') + +tracks = """ +[bigwig op test] +file = bigwig3_X_2.5e6_3.5e6.bw +second_file = bigwig_chrx_2e6_5e6.bw +# height of the track in cm (optional value) +operation = file - second_file +height = 4 +title = file - second_file +""" + +with open(os.path.join(ROOT, "example_op.ini"), 'w') as fh: + fh.write(tracks) + tolerance = 13 # default matplotlib pixed difference tolerance def test_bigwig_track(): + outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_test_', + delete=False) + ini_file = os.path.join(ROOT, "bigwig.ini") region = "X:2700000-3100000" - outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_test_', delete=False) - args = "--tracks {ini} --region {region} --trackLabelFraction 0.2 " \ - "--dpi 130 --outFileName {outfile}" \ - "".format(ini=os.path.join(ROOT, "bigwig.ini"), - outfile=outfile.name, region=region).split() + expected_file = os.path.join(ROOT, 'master_bigwig.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_bigwig.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -352,15 +450,16 @@ def test_bigwig_track(): def test_alpha(): + outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_alpha_test_', + delete=False) + ini_file = os.path.join(ROOT, "alpha.ini") region = "X:2700000-3100000" - outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_alpha_test_', delete=False) - args = "--tracks {ini} --region {region} --trackLabelFraction 0.2 " \ - "--dpi 130 --outFileName {outfile}" \ - "".format(ini=os.path.join(ROOT, "alpha.ini"), - outfile=outfile.name, region=region).split() + expected_file = os.path.join(ROOT, 'master_alpha.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_alpha.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -368,31 +467,106 @@ def test_alpha(): def test_hlines(): + outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_hlines_test_', + delete=False) + ini_file = os.path.join(ROOT, "hlines.ini") region = "X:2700000-3100000" - outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_hlines_test_', delete=False) - args = "--tracks {ini} --region {region} --trackLabelFraction 0.2 " \ - "--dpi 130 --outFileName {outfile}" \ - "".format(ini=os.path.join(ROOT, "hlines.ini"), - outfile=outfile.name, region=region).split() + expected_file = os.path.join(ROOT, 'master_hlines.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_hlines.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res os.remove(outfile.name) -def test_op(): +def test_grid(): + outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_grid_test_', + delete=False) + ini_file = os.path.join(ROOT, "grid.ini") region = "X:2700000-3100000" - outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_op_test_', delete=False) - args = "--tracks {ini} --region {region} --trackLabelFraction 0.2 " \ - "--dpi 130 --outFileName {outfile}" \ - "".format(ini=os.path.join(ROOT, "operation.ini"), - outfile=outfile.name, region=region).split() + expected_file = os.path.join(ROOT, 'master_grid.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_op(): + outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_op_test_', + delete=False) + for pref in ['', 'incorrect_']: + ini_file = os.path.join(ROOT, f"{pref}operation.ini") + region = "X:2700000-3100000" + expected_file = os.path.join(ROOT, 'master_operation.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + if 'incorrect' in ini_file: + os.remove(ini_file) + + +def test_op_fakeChr(): + outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_op_test_', + delete=False) + ini_file = os.path.join(ROOT, "operation.ini") + region = "fakeChr:2700000-3100000" + expected_file = os.path.join(ROOT, 'master_operation_fakeChr.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_defaults(): + region = "X:2,500,000-3,000,000" + for suf in [''] + ['_invalid_custom_color' + s for s in ['', '2', '3']] + \ + ['_invalid_transform']: + outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_test_', + delete=False) + ini_file = os.path.join(ROOT, f"example_bigwig{suf}.ini") + expected_file = os.path.join(ROOT, 'master_example_bigwig.png') + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + if 'invalid' in ini_file: + os.remove(ini_file) + + +def test_op_chr_in_only_one_bw(): + outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_op_test_', + delete=False) + ini_file = os.path.join(ROOT, "example_op.ini") + region = "2L:0-1000" + expected_file = os.path.join(ROOT, 'master_operation_2L.png') + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_operation.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res diff --git a/pygenometracks/tests/test_checker.py b/pygenometracks/tests/test_checker.py index 533b48a3..c11860ac 100644 --- a/pygenometracks/tests/test_checker.py +++ b/pygenometracks/tests/test_checker.py @@ -11,7 +11,7 @@ ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), - "test_data", "uncorrect_ini_files") + "test_data") test_tracks_1 = """ [vlines] @@ -101,6 +101,97 @@ with open(os.path.join(ROOT, "test_tracks_11.ini"), 'w') as fh: fh.write(test_tracks_11) +test_tracks_12 = """ +[operation without second_file] +file = bigwig_chrx_2e6_5e6.bw +operation = file - second_file +""" +with open(os.path.join(ROOT, "test_tracks_12.ini"), 'w') as fh: + fh.write(test_tracks_12) + +test_tracks_12b = """ +[operation without second_file] +file = bedgraph2_X_2.5e6_3.5e6.bdg +operation = file - second_file +""" +with open(os.path.join(ROOT, "test_tracks_12b.ini"), 'w') as fh: + fh.write(test_tracks_12) + +test_tracks_13 = """ +[operation with transform] +file = bigwig_chrx_2e6_5e6.bw +operation = file + 1 +transform = log +""" +with open(os.path.join(ROOT, "test_tracks_13.ini"), 'w') as fh: + fh.write(test_tracks_13) + +test_tracks_13b = """ +[operation with transform] +file = bedgraph2_X_2.5e6_3.5e6.bdg +operation = file + 1 +transform = log +""" +with open(os.path.join(ROOT, "test_tracks_13b.ini"), 'w') as fh: + fh.write(test_tracks_13b) + +test_tracks_14 = """ +[invalid operation] +file = bigwig_chrx_2e6_5e6.bw +operation = file + a +""" +with open(os.path.join(ROOT, "test_tracks_14.ini"), 'w') as fh: + fh.write(test_tracks_14) + +test_tracks_14b = """ +[invalid operation] +file = bedgraph2_X_2.5e6_3.5e6.bdg +operation = file + a +""" +with open(os.path.join(ROOT, "test_tracks_14b.ini"), 'w') as fh: + fh.write(test_tracks_14b) + +test_tracks_15 = """ +[invalid operation with 2 files] +file = bigwig_chrx_2e6_5e6.bw +second_file = bigwig_chrx_2e6_5e6.bw +operation = file + a * second_file +""" +with open(os.path.join(ROOT, "test_tracks_15.ini"), 'w') as fh: + fh.write(test_tracks_15) + +test_tracks_15b = """ +[invalid operation with 2 files] +file = bedgraph2_X_2.5e6_3.5e6.bdg +second_file = bedgraph2_X_2.5e6_3.5e6.bdg +operation = file + a * second_file +""" +with open(os.path.join(ROOT, "test_tracks_15b.ini"), 'w') as fh: + fh.write(test_tracks_15b) + + +test_tracks_16 = """ +[x-axis] + +[bedgraph] +file = bedgraph2_X_2.5e6_3.5e6.bdg +overlay_previous = anything +""" +with open(os.path.join(ROOT, "test_tracks_16.ini"), 'w') as fh: + fh.write(test_tracks_16) + + +test_tracks_17 = """ +[x-axis] + +[vlines] +file = tad_classification.bed +type = vlines +line_width = a +""" +with open(os.path.join(ROOT, "test_tracks_17.ini"), 'w') as fh: + fh.write(test_tracks_17) + class TestCheckerMethods(unittest.TestCase): @@ -112,14 +203,15 @@ def test_vline_without_file(self): there is no file """ outfile_name = "test.png" - args = "--tracks {0} --region X:3000000-3300000 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "test_tracks_1.ini"), - outfile_name).split() + ini_file = os.path.join(ROOT, "test_tracks_1.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() with self.assertRaises(InputError) as context: pygenometracks.plotTracks.main(args) assert("there is no file" in str(context.exception)) + os.remove(ini_file) def test_missing_file_type(self): """ @@ -129,15 +221,16 @@ def test_missing_file_type(self): file_type ... does not exists """ outfile_name = "test.png" - args = "--tracks {0} --region X:3000000-3300000 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "test_tracks_2.ini"), - outfile_name).split() + ini_file = os.path.join(ROOT, "test_tracks_2.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() with self.assertRaises(InputError) as context: pygenometracks.plotTracks.main(args) assert("file_type newFileTypeIJustInvented does not exists" in str(context.exception)) + os.remove(ini_file) def test_unguessable_file_type_no_file(self): """ @@ -147,15 +240,16 @@ def test_unguessable_file_type_no_file(self): there is no file_type nor file """ outfile_name = "test.png" - args = "--tracks {0} --region X:3000000-3300000 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "test_tracks_3.ini"), - outfile_name).split() + ini_file = os.path.join(ROOT, "test_tracks_3.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() with self.assertRaises(InputError) as context: pygenometracks.plotTracks.main(args) assert(" there is no file_type nor file " in str(context.exception)) + os.remove(ini_file) def test_missing_necessary_option(self): """ @@ -167,14 +261,15 @@ def test_missing_necessary_option(self): the necessary property """ outfile_name = "test.png" - args = "--tracks {0} --region X:3000000-3300000 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "test_tracks_4.ini"), - outfile_name).split() + ini_file = os.path.join(ROOT, "test_tracks_4.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() with self.assertRaises(InputError) as context: pygenometracks.plotTracks.main(args) assert("the necessary property" in str(context.exception)) + os.remove(ini_file) def test_boolean(self): """ @@ -184,14 +279,15 @@ def test_boolean(self): boolean """ outfile_name = "test.png" - args = "--tracks {0} --region X:3000000-3300000 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "test_tracks_5.ini"), - outfile_name).split() + ini_file = os.path.join(ROOT, "test_tracks_5.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() with self.assertRaises(InputError) as context: pygenometracks.plotTracks.main(args) assert("boolean" in str(context.exception)) + os.remove(ini_file) def test_float(self): """ @@ -201,14 +297,15 @@ def test_float(self): float """ outfile_name = "test.png" - args = "--tracks {0} --region X:3000000-3300000 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "test_tracks_6.ini"), - outfile_name).split() + ini_file = os.path.join(ROOT, "test_tracks_6.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() with self.assertRaises(InputError) as context: pygenometracks.plotTracks.main(args) assert("float" in str(context.exception)) + os.remove(ini_file) def test_float_limit(self): """ @@ -219,14 +316,15 @@ def test_float_limit(self): whereas it should be between """ outfile_name = "test.png" - args = "--tracks {0} --region X:3000000-3300000 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "test_tracks_7.ini"), - outfile_name).split() + ini_file = os.path.join(ROOT, "test_tracks_7.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() with self.assertRaises(InputError) as context: pygenometracks.plotTracks.main(args) assert("whereas it should be between" in str(context.exception)) + os.remove(ini_file) def test_integer(self): """ @@ -236,14 +334,15 @@ def test_integer(self): integer """ outfile_name = "test.png" - args = "--tracks {0} --region X:3000000-3300000 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "test_tracks_8.ini"), - outfile_name).split() + ini_file = os.path.join(ROOT, "test_tracks_8.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() with self.assertRaises(InputError) as context: pygenometracks.plotTracks.main(args) assert("integer" in str(context.exception)) + os.remove(ini_file) def test_integer_limit(self): """ @@ -254,14 +353,15 @@ def test_integer_limit(self): whereas it should be between """ outfile_name = "test.png" - args = "--tracks {0} --region X:3000000-3300000 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "test_tracks_9.ini"), - outfile_name).split() + ini_file = os.path.join(ROOT, "test_tracks_9.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() with self.assertRaises(InputError) as context: pygenometracks.plotTracks.main(args) assert("whereas it should be between" in str(context.exception)) + os.remove(ini_file) def test_file_missing(self): """ @@ -271,15 +371,16 @@ def test_file_missing(self): File in section ... not found """ outfile_name = "test.png" - args = "--tracks {0} --region X:3000000-3300000 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "test_tracks_10.ini"), - outfile_name).split() + ini_file = os.path.join(ROOT, "test_tracks_10.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() with self.assertRaises(InputError) as context: pygenometracks.plotTracks.main(args) assert("File in section [1. [inexisting file]] not found" in str(context.exception)) + os.remove(ini_file) def test_unguessable_file_type(self): """ @@ -291,11 +392,203 @@ def test_unguessable_file_type(self): can not identify file type """ outfile_name = "test.png" - args = "--tracks {0} --region X:3000000-3300000 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "test_tracks_11.ini"), - outfile_name).split() + ini_file = os.path.join(ROOT, "test_tracks_11.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() with self.assertRaises(InputError) as context: pygenometracks.plotTracks.main(args) assert("can not identify file type" in str(context.exception)) + os.remove(ini_file) + + def test_operation_bw_without_second_file(self): + """ + This test check that if you provide + a second_file if second_file is part of the + operation. + """ + outfile_name = "test.png" + for suf in ['', 'b']: + ini_file = os.path.join(ROOT, f"test_tracks_12{suf}.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() + with self.assertRaises(InputError) as context: + pygenometracks.plotTracks.main(args) + + assert("requires to set the parameter second_file" in + str(context.exception)) + os.remove(ini_file) + + def test_operation_with_transform(self): + """ + This test check that if you do not provide + both an operation and a transform. + """ + outfile_name = "test.png" + for suf in ['', 'b']: + ini_file = os.path.join(ROOT, f"test_tracks_13{suf}.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() + with self.assertRaises(InputError) as context: + pygenometracks.plotTracks.main(args) + + assert("'operation' and 'transform' cannot be set at the same time." + in str(context.exception)) + os.remove(ini_file) + + def test_invalid_operation(self): + """ + This test check that if you give an invalid operation + it will fail. + """ + outfile_name = "test.png" + for suf in ['', 'b']: + ini_file = os.path.join(ROOT, f"test_tracks_14{suf}.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() + with self.assertRaises(Exception) as context: + pygenometracks.plotTracks.main(args) + + assert("could not be computed" + in str(context.exception)) + os.remove(ini_file) + + def test_invalid_operation2(self): + """ + This test check that if you give an invalid operation + it will fail. + """ + outfile_name = "test.png" + for suf in ['', 'b']: + ini_file = os.path.join(ROOT, f"test_tracks_15{suf}.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() + with self.assertRaises(Exception) as context: + pygenometracks.plotTracks.main(args) + + assert("could not be computed" + in str(context.exception)) + os.remove(ini_file) + + def test_wrong_overlay_previous(self): + """ + This test check that if you provide + an overlay_previous which is not no, yes, share-y + you will have an error with a message containing + Possible options are no, yes, share-y + """ + outfile_name = "test.png" + ini_file = os.path.join(ROOT, "test_tracks_16.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() + with self.assertRaises(InputError) as context: + pygenometracks.plotTracks.main(args) + + assert("Possible options are no, yes, share-y" in str(context.exception)) + os.remove(ini_file) + + def test_wrong_line_width_vlines(self): + """ + This test check that if you provide + an line_width which is not float + you will have an error with a message containing + whereas we should have a float + """ + outfile_name = "test.png" + ini_file = os.path.join(ROOT, "test_tracks_17.ini") + region = "X:3000000-3300000" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() + with self.assertRaises(InputError) as context: + pygenometracks.plotTracks.main(args) + + assert("whereas we should have a float" in str(context.exception)) + os.remove(ini_file) + + +class TestInputRegionMethods(unittest.TestCase): + + def test_region_format_onlychr(self): + """ + This test check that you get an error + if the region format is not good + """ + outfile_name = "test.png" + ini_file = os.path.join(ROOT, "empty.ini") + region = "X" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() + with self.assertRaises(InputError) as context: + pygenometracks.plotTracks.main(args) + + assert("is not valid, it should be chr:start-end" in + str(context.exception)) + + def test_region_format_chr_only_start(self): + """ + This test check that you get an error + if the region format is not good + """ + outfile_name = "test.png" + ini_file = os.path.join(ROOT, "empty.ini") + region = "X:12" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() + with self.assertRaises(Exception) as context: + pygenometracks.plotTracks.main(args) + + assert("is not valid, it should be chr:start-end" in + str(context.exception)) + + def test_region_format_invalid_start(self): + """ + This test check that you get an error + if the region format is not good + """ + outfile_name = "test.png" + ini_file = os.path.join(ROOT, "empty.ini") + for region in ['X:a-12', 'X:-3']: + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() + with self.assertRaises(InputError) as context: + pygenometracks.plotTracks.main(args) + + assert("is not valid, it should be chr:start-end" in + str(context.exception)) + + def test_region_format_invalid_end(self): + """ + This test check that you get an error + if the region format is not good + """ + outfile_name = "test.png" + ini_file = os.path.join(ROOT, "empty.ini") + region = "X:12-1d" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() + with self.assertRaises(InputError) as context: + pygenometracks.plotTracks.main(args) + + assert("is not valid, it should be chr:start-end" in + str(context.exception)) + + def test_region_format_start_smaller_end(self): + """ + This test check that you get an error + if the region format is not good + """ + outfile_name = "test.png" + ini_file = os.path.join(ROOT, "empty.ini") + region = "X:12-1" + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile_name}".split() + with self.assertRaises(InputError) as context: + pygenometracks.plotTracks.main(args) + + assert("end is larger" in str(context.exception)) diff --git a/pygenometracks/tests/test_data/arcs_invalid.arcs b/pygenometracks/tests/test_data/arcs_invalid.arcs new file mode 100644 index 00000000..6aaeb2db --- /dev/null +++ b/pygenometracks/tests/test_data/arcs_invalid.arcs @@ -0,0 +1,3 @@ +chrX 3000000 3000001 chrX 3010000 +chrX 3030000 3030001 chrX 3080000 +chrX 3030000 3030001 chrX 3200000 diff --git a/pygenometracks/tests/test_data/arcs_invalid2.arcs b/pygenometracks/tests/test_data/arcs_invalid2.arcs new file mode 100644 index 00000000..4d960f91 --- /dev/null +++ b/pygenometracks/tests/test_data/arcs_invalid2.arcs @@ -0,0 +1,3 @@ +chrX 3000000 3000001 chrX 3010000 3010001 100 +chrX 3030000 3030001 chrY 3200000 3200001 2 +chrX 3030000 3030001 chrX 3080000 a 50 diff --git a/pygenometracks/tests/test_data/arcs_invalid_score.arcs b/pygenometracks/tests/test_data/arcs_invalid_score.arcs new file mode 100644 index 00000000..2125c866 --- /dev/null +++ b/pygenometracks/tests/test_data/arcs_invalid_score.arcs @@ -0,0 +1,3 @@ +chrX 3000000 3000001 chrX 3010000 3010001 a +chrX 3030000 3030001 chrX 3080000 3080001 0.5 +chrX 3030000 3030001 chrX 3200000 3200001 2 diff --git a/pygenometracks/tests/test_data/arcs_invalid_score2.arcs b/pygenometracks/tests/test_data/arcs_invalid_score2.arcs new file mode 100644 index 00000000..5a05f8c2 --- /dev/null +++ b/pygenometracks/tests/test_data/arcs_invalid_score2.arcs @@ -0,0 +1,3 @@ +chrX 3000000 3000001 chrX 3010000 3010001 1 +chrX 3030000 3030001 chrX 3080000 3080001 0.5 +chrX 3030000 3030001 chrX 3200000 3200001 a diff --git a/pygenometracks/tests/test_data/arcs_no_score.ini b/pygenometracks/tests/test_data/arcs_no_score.ini new file mode 100644 index 00000000..e327a3c4 --- /dev/null +++ b/pygenometracks/tests/test_data/arcs_no_score.ini @@ -0,0 +1,23 @@ + +[arcs] +title = loop with scores +file = test_high_score.arcs +color = cividis +height = 2 +links_type = loops + +[arcs] +title = arcs with scores +file = test_high_score.arcs +color = cividis +height = 2 +min_value = 0 +max_value = 80 + +[arcs] +title = arcs without scores +file = test_noscore.arcs +color = blue +line_width = 0.5 +height = 2 + diff --git a/pygenometracks/tests/test_data/arcs_use_middle.ini b/pygenometracks/tests/test_data/arcs_use_middle.ini new file mode 100644 index 00000000..40b5a309 --- /dev/null +++ b/pygenometracks/tests/test_data/arcs_use_middle.ini @@ -0,0 +1,57 @@ + +[x-axis] +where = top + +[spacer] +height = 0.05 +[hic matrix] +file = Li_et_al_2015.cool +title = depth = 300000; transform = log1p; min_value = 5 (next track: overlay_previous = share-y links_type = loops) +depth = 300000 +min_value = 5 +transform = log1p +file_type = hic_matrix +show_masked_bins = false + +[test arcs overlay] +file = test_wide.arcs +color = red +line_width = 5 +links_type = loops +overlay_previous = share-y + +[test arcs] +file = test_wide.arcs +line_width = 3 +color = RdYlGn +title = links line_width = 3 color RdYlGn +height = 3 +orientation = inverted + +[spacer] +height = 1 + +[hic matrix] +file = Li_et_al_2015.cool +title = depth = 300000; transform = log1p; min_value = 5 (next track: overlay_previous = share-y links_type = loops) +depth = 300000 +min_value = 5 +transform = log1p +file_type = hic_matrix +show_masked_bins = false + +[test arcs overlay] +file = test_wide.arcs +color = red +line_width = 5 +links_type = loops +overlay_previous = share-y + +[test arcs] +file = test_wide.arcs +line_width = 3 +color = RdYlGn +title = links line_width = 3 color RdYlGn use_middle = true +use_middle = true +height = 3 +orientation = inverted diff --git a/pygenometracks/tests/test_data/bed_colormap_genes.ini b/pygenometracks/tests/test_data/bed_colormap_genes.ini index 8b3c2638..5058a8e6 100644 --- a/pygenometracks/tests/test_data/bed_colormap_genes.ini +++ b/pygenometracks/tests/test_data/bed_colormap_genes.ini @@ -32,7 +32,9 @@ height = 10.0 [scores in cod+utr 2] file = dm3_genes_withrgbandscore.bed.gz -title = genes with scores both in coding and utr as Reds +title = genes with scores both in coding and utr as Reds min_value = 0.2 max_value = 2 color = Reds color_utr = Reds height = 10.0 +min_value = 0.2 +max_value = 2 diff --git a/pygenometracks/tests/test_data/bed_different_UTR.ini b/pygenometracks/tests/test_data/bed_different_UTR.ini new file mode 100644 index 00000000..4012a332 --- /dev/null +++ b/pygenometracks/tests/test_data/bed_different_UTR.ini @@ -0,0 +1,26 @@ + +[genes1] +file = example.bed +title = bed style = flybase +style = flybase +height = 4 + +[spacer] + +[genes2] +file = example.bed +title = bed style = UCSC +style = UCSC +height = 4 + +[spacer] + +[genes1] +file = example.bed +title = bed style = tssarrow +style = tssarrow +height = 4 + +[spacer] + +[x-axis] diff --git a/pygenometracks/tests/test_data/bed_shuffle.ini b/pygenometracks/tests/test_data/bed_shuffle.ini new file mode 100644 index 00000000..6943691a --- /dev/null +++ b/pygenometracks/tests/test_data/bed_shuffle.ini @@ -0,0 +1,25 @@ + +[genes] +file = dm3_genes_withrgbandscore.bed.gz +title = bed color = Reds +color = Reds +height = 4 + +[spacer] + +[genes] +file = dm3_genes_withrgbandscore_shuffled.bed.gz +title = bed color = Reds bed is not sorted +color = Reds +height = 4 + +[spacer] + +[genes] +file = dm3_genes_withrgbandscore_shuffled.bed.gz +title = bed color = Reds global_max_row = true and bed is not sorted +color = Reds +global_max_row = true +height = 4 + +[x-axis] diff --git a/pygenometracks/tests/test_data/bed_vlines.ini b/pygenometracks/tests/test_data/bed_vlines.ini new file mode 100644 index 00000000..b6eb8025 --- /dev/null +++ b/pygenometracks/tests/test_data/bed_vlines.ini @@ -0,0 +1,17 @@ + +[genes] +file = dm3_genes_withrgbandscore.bed.gz +title = bed global_max_row = true labels = false +labels = false +global_max_row = true +height = 4 + +[spacer] + +[x-axis] +title = centered title + +[vlines] +file = tad_classification.bed +type = vlines +line_width = 3 diff --git a/pygenometracks/tests/test_data/bedgraph_negative.ini b/pygenometracks/tests/test_data/bedgraph_negative.ini new file mode 100644 index 00000000..c92b73a9 --- /dev/null +++ b/pygenometracks/tests/test_data/bedgraph_negative.ini @@ -0,0 +1,26 @@ + +[x-axis] +where = top + +[test bedgraph neg] +file = test_with_neg_values.bg.gz +color = blue +negative_color = red +title = color = blue; negative_color = red +height = 5 + +[test bedgraph neg] +file = test_with_neg_values.bg.gz +color = cyan +negative_color = darkred +type = line:2 +title = color = cyan; negative_color = darkred; type = line:2 +height = 5 + +[test bedgraph neg] +file = test_with_neg_values.bg.gz +color = black +negative_color = lime +type = points:2 +title = color = black; negative_color = lime; type = points:2 +height = 5 diff --git a/pygenometracks/tests/test_data/bedgraph_withNA.bdg b/pygenometracks/tests/test_data/bedgraph_withNA.bdg new file mode 100644 index 00000000..10fe30d1 --- /dev/null +++ b/pygenometracks/tests/test_data/bedgraph_withNA.bdg @@ -0,0 +1,12 @@ +browser position chrX:2000000-3500000 +browser hide all +browser pack refGene encodeRegions +browser full altGraph +# 300 base wide bar graph, autoScale is on by default == graphing +# limits will dynamically change to always show full range of data +# in viewing window, priority = 20 positions this as the second graph +# Note, zero-relative, half-open coordinate system in use for bedGraph format +track type=bedGraph name="BedGraph Format" description="BedGraph format" visibility=full color=200,100,0 altColor=0,100,200 priority=20 +chrX 2000000 3000000 1 +chrX 3000000 3070000 NA +chrX 3080750 4000800 2 diff --git a/pygenometracks/tests/test_data/bedgraph_withNA.ini b/pygenometracks/tests/test_data/bedgraph_withNA.ini new file mode 100644 index 00000000..eee062e6 --- /dev/null +++ b/pygenometracks/tests/test_data/bedgraph_withNA.ini @@ -0,0 +1,6 @@ + +[test bedgraph withNA] +file = bedgraph_withNA.bdg +height = 3 + +[x-axis] diff --git a/pygenometracks/tests/test_data/bigwig.ini b/pygenometracks/tests/test_data/bigwig.ini index 5760879f..3b314f75 100644 --- a/pygenometracks/tests/test_data/bigwig.ini +++ b/pygenometracks/tests/test_data/bigwig.ini @@ -15,6 +15,8 @@ color = red height = 2 type = line:0.2 title = type = line:0.2 +min_value = auto +max_value = auto [spacer] diff --git a/pygenometracks/tests/test_data/bigwig3_X_2.5e6_3.5e6.bw b/pygenometracks/tests/test_data/bigwig3_X_2.5e6_3.5e6.bw new file mode 100644 index 00000000..beb028d4 Binary files /dev/null and b/pygenometracks/tests/test_data/bigwig3_X_2.5e6_3.5e6.bw differ diff --git a/pygenometracks/tests/test_data/browser_tracks_hic_one_interaction_cool.ini b/pygenometracks/tests/test_data/browser_tracks_hic_one_interaction_cool.ini new file mode 100644 index 00000000..2887ed87 --- /dev/null +++ b/pygenometracks/tests/test_data/browser_tracks_hic_one_interaction_cool.ini @@ -0,0 +1,32 @@ + +[hic matrix] +file = one_interaction_4chr.cool +title = cool with one interaction show_masked_bins = false +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = false + +[spacer] + +[hic matrix] +file = one_interaction_4chr.cool +title = cool with one interaction show_masked_bins = true +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = true + +[spacer] + +[hic matrix] +file = one_interaction_4chr.cool +title = cool with one interaction show_masked_bins = true transform = log +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = true +transform = log + +[newtrack] +file_type = x_axis diff --git a/pygenometracks/tests/test_data/browser_tracks_hic_one_interaction_diag_h5.ini b/pygenometracks/tests/test_data/browser_tracks_hic_one_interaction_diag_h5.ini new file mode 100644 index 00000000..9c9625c5 --- /dev/null +++ b/pygenometracks/tests/test_data/browser_tracks_hic_one_interaction_diag_h5.ini @@ -0,0 +1,32 @@ + +[hic matrix] +file = one_interaction_diag_4chr.h5 +title = cool with one interaction show_masked_bins = false +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = false + +[spacer] + +[hic matrix] +file = one_interaction_diag_4chr.h5 +title = cool with one interaction show_masked_bins = true +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = true + +[spacer] + +[hic matrix] +file = one_interaction_diag_4chr.h5 +title = cool with one interaction show_masked_bins = true transform = log +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = true +transform = log + +[newtrack] +file_type = x_axis diff --git a/pygenometracks/tests/test_data/browser_tracks_hic_one_interaction_h5.ini b/pygenometracks/tests/test_data/browser_tracks_hic_one_interaction_h5.ini new file mode 100644 index 00000000..41383a12 --- /dev/null +++ b/pygenometracks/tests/test_data/browser_tracks_hic_one_interaction_h5.ini @@ -0,0 +1,32 @@ + +[hic matrix] +file = one_interaction_4chr.h5 +title = cool with one interaction show_masked_bins = false +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = false + +[spacer] + +[hic matrix] +file = one_interaction_4chr.h5 +title = cool with one interaction show_masked_bins = true +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = true + +[spacer] + +[hic matrix] +file = one_interaction_4chr.h5 +title = cool with one interaction show_masked_bins = true transform = log +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = true +transform = log + +[newtrack] +file_type = x_axis diff --git a/pygenometracks/tests/test_data/browser_tracks_hic_rasterize_height.ini b/pygenometracks/tests/test_data/browser_tracks_hic_rasterize_height.ini index e9d46f00..6bca07c6 100644 --- a/pygenometracks/tests/test_data/browser_tracks_hic_rasterize_height.ini +++ b/pygenometracks/tests/test_data/browser_tracks_hic_rasterize_height.ini @@ -1,6 +1,6 @@ [hic matrix] -file = Li_et_al_2015.h5 +file = Li_et_al_2015.cool title = depth = 200000; transform = log1p; min_value = 5; height = 5 depth = 200000 min_value = 5 diff --git a/pygenometracks/tests/test_data/browser_tracks_hic_small_test.ini b/pygenometracks/tests/test_data/browser_tracks_hic_small_test.ini new file mode 100644 index 00000000..ca63e303 --- /dev/null +++ b/pygenometracks/tests/test_data/browser_tracks_hic_small_test.ini @@ -0,0 +1,19 @@ + +[hic matrix] +file = small_test2.cool +title = cool with few interactions show_masked_bins = false (default) +depth = 200000 +file_type = hic_matrix +height = 5 + +[spacer] + +[hic matrix] +file = small_test2.cool +title = cool with few interactions show_masked_bins = true +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = true + +[x-axis] diff --git a/pygenometracks/tests/test_data/browser_tracks_hic_small_test_2.ini b/pygenometracks/tests/test_data/browser_tracks_hic_small_test_2.ini new file mode 100644 index 00000000..5b1aa9ce --- /dev/null +++ b/pygenometracks/tests/test_data/browser_tracks_hic_small_test_2.ini @@ -0,0 +1,9 @@ + +[hic matrix] +file = small_test2.cool +title = cool with few interactions depth=10kb +file_type = hic_matrix +depth = 10000 + + +[x-axis] diff --git a/pygenometracks/tests/test_data/browser_tracks_hic_small_test_3.ini b/pygenometracks/tests/test_data/browser_tracks_hic_small_test_3.ini new file mode 100644 index 00000000..85dd6847 --- /dev/null +++ b/pygenometracks/tests/test_data/browser_tracks_hic_small_test_3.ini @@ -0,0 +1,37 @@ + +[hic matrix] +file = small_test3.cool +title = cool with few interactions transform = no +depth = 200000 +file_type = hic_matrix +min_value = 0 +max_value = 50 + +[hic matrix] +file = small_test3.cool +title = cool with few interactions transform = log +transform = log +depth = 200000 +file_type = hic_matrix +min_value = 0 +max_value = 5 + +[hic matrix] +file = small_test3.cool +title = cool with few interactions transform = -log +transform = -log +depth = 200000 +file_type = hic_matrix +min_value = 0 +max_value = -5 + +[hic matrix] +file = small_test3.cool +title = cool with few interactions transform = log1p +transform = log1p +depth = 200000 +file_type = hic_matrix +min_value = 0.1 +max_value = 50 + +[x-axis] diff --git a/pygenometracks/tests/test_data/dm3_genes.bed4.gz b/pygenometracks/tests/test_data/dm3_genes.bed4.gz index 18972545..667ec7c1 100644 Binary files a/pygenometracks/tests/test_data/dm3_genes.bed4.gz and b/pygenometracks/tests/test_data/dm3_genes.bed4.gz differ diff --git a/pygenometracks/tests/test_data/dm3_genes_withrgbandscore.bed.gz b/pygenometracks/tests/test_data/dm3_genes_withrgbandscore.bed.gz index d7542b7c..3346cc95 100644 Binary files a/pygenometracks/tests/test_data/dm3_genes_withrgbandscore.bed.gz and b/pygenometracks/tests/test_data/dm3_genes_withrgbandscore.bed.gz differ diff --git a/pygenometracks/tests/test_data/dm3_genes_withrgbandscore_shuffled.bed.gz b/pygenometracks/tests/test_data/dm3_genes_withrgbandscore_shuffled.bed.gz new file mode 100644 index 00000000..44a1de45 Binary files /dev/null and b/pygenometracks/tests/test_data/dm3_genes_withrgbandscore_shuffled.bed.gz differ diff --git a/pygenometracks/tests/test_data/example.bed b/pygenometracks/tests/test_data/example.bed new file mode 100644 index 00000000..4217dd69 --- /dev/null +++ b/pygenometracks/tests/test_data/example.bed @@ -0,0 +1,10 @@ +chr1 0 100 pos_two_blocks_no_5p_UTR 0 + 0 80 0,0,255 2 20,30 0,70 +chr1 0 100 pos_two_blocks_no_3p_UTR 0 + 15 100 0,0,255 2 20,30 0,70 +chr1 0 100 pos_one_block 0 + 20 50 255,0,255 1 100, 0, +chr1 0 100 pos_one_block_CDS_at_start 0 + 0 0 0,0,255 1 100, 0, +chr1 0 100 pos_one_block_CDS_full 0 + 0 100 255,0,255 1 100, 0, +chr1 200 300 neg_one_block_CDS_full 0 - 200 300 255,0,255 1 100, 0, +chr1 200 300 neg_two_blocks_no_5p_UTR 0 - 200 280 0,0,255 2 20,30 0,70 +chr1 200 300 neg_two_blocks_no_3p_UTR 0 - 215 300 0,0,255 2 20,30 0,70 +chr1 350 400 no_strand_two_blocks 0 . 360 390 0,0,255 2 20,20 0,30 + diff --git a/pygenometracks/tests/test_data/example_bigwig.ini b/pygenometracks/tests/test_data/example_bigwig.ini new file mode 100644 index 00000000..d1564884 --- /dev/null +++ b/pygenometracks/tests/test_data/example_bigwig.ini @@ -0,0 +1,8 @@ + +[bigwig file test] +file = bigwig_chrx_2e6_5e6.bw +# height of the track in cm (optional value) +height = 4 +title = bigwig +min_value = 0 +max_value = 30 diff --git a/pygenometracks/tests/test_data/example_op.ini b/pygenometracks/tests/test_data/example_op.ini new file mode 100644 index 00000000..94c9a39f --- /dev/null +++ b/pygenometracks/tests/test_data/example_op.ini @@ -0,0 +1,8 @@ + +[bigwig op test] +file = bigwig3_X_2.5e6_3.5e6.bw +second_file = bigwig_chrx_2e6_5e6.bw +# height of the track in cm (optional value) +operation = file - second_file +height = 4 +title = file - second_file diff --git a/pygenometracks/tests/test_data/example_zeroBlock.bed b/pygenometracks/tests/test_data/example_zeroBlock.bed new file mode 100644 index 00000000..803eb2e1 --- /dev/null +++ b/pygenometracks/tests/test_data/example_zeroBlock.bed @@ -0,0 +1,10 @@ +chr1 0 100 pos_two_blocks_no_5p_UTR 0 + 0 80 0,0,255 2 20,30 0,70 +chr1 0 100 pos_two_blocks_no_3p_UTR 0 + 15 100 0,0,255 2 20,30 0,70 +chr1 0 100 pos_zero_block 0 + 20 50 255,0,255 0 +chr1 0 100 pos_zero_block_CDS_at_start 0 + 0 0 0,0,255 0 +chr1 0 100 pos_zero_block_CDS_full 0 + 0 100 255,0,255 0 +chr1 200 300 neg_zero_block_CDS_full 0 - 200 300 255,0,255 0 +chr1 200 300 neg_two_blocks_no_5p_UTR 0 - 200 280 0,0,255 2 20,30 0,70 +chr1 200 300 neg_two_blocks_no_3p_UTR 0 - 215 300 0,0,255 2 20,30 0,70 +chr1 350 400 no_strand_two_blocks 0 . 360 390 0,0,255 2 20,20 0,30 + diff --git a/pygenometracks/tests/test_data/firstTrackOverlay.ini b/pygenometracks/tests/test_data/firstTrackOverlay.ini new file mode 100644 index 00000000..9353e7e9 --- /dev/null +++ b/pygenometracks/tests/test_data/firstTrackOverlay.ini @@ -0,0 +1,4 @@ + +[bed] +file = empty.bed +overlay_previous = yes diff --git a/pygenometracks/tests/test_data/grid.ini b/pygenometracks/tests/test_data/grid.ini new file mode 100644 index 00000000..cf5b51fc --- /dev/null +++ b/pygenometracks/tests/test_data/grid.ini @@ -0,0 +1,49 @@ + +[test bigwig fill] +file = bigwig2_X_2.5e6_3.5e6.bw +color = black +height = 2 +type = fill +title = bigwig: black fill (height = 2) + +[test bigwig fill with grid] +file = bigwig2_X_2.5e6_3.5e6.bw +color = black +height = 2 +type = fill +grid = true +title = bigwig: black fill with grid (height = 2) + +[spacer] + +[test bigwig fill with grid] +file = bigwig2_X_2.5e6_3.5e6.bw +color = black +height = 5 +type = fill +grid = true +title = bigwig: black fill with grid (height = 5) + +[spacer] + +[test bigwig fill with grid] +file = bigwig2_X_2.5e6_3.5e6.bw +color = black +height = 5 +type = fill +grid = true +max_value = 50 +title = bigwig: black fill with grid (height = 5 max_value = 50) + +[spacer] + +[test bigwig fill with grid] +file = bigwig2_X_2.5e6_3.5e6.bw +color = black +height = 15 +type = fill +grid = true +max_value = 50 +title = bigwig: black fill with grid (height = 15 max_value = 50) + +[x-axis] diff --git a/pygenometracks/tests/test_data/invalid_CDScoo.bed b/pygenometracks/tests/test_data/invalid_CDScoo.bed new file mode 100644 index 00000000..08b9dbb8 --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_CDScoo.bed @@ -0,0 +1,3 @@ +chrX 16000 18000 pos 0 + a 17500 255 +chrX 20000 21000 neg 0 - 20200 20500 255,0,0 +chrX 22000 23400 no_strand 0 . 22000 23400 0,255,0 \ No newline at end of file diff --git a/pygenometracks/tests/test_data/invalid_CDScoo.ini b/pygenometracks/tests/test_data/invalid_CDScoo.ini new file mode 100644 index 00000000..b891aca4 --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_CDScoo.ini @@ -0,0 +1,22 @@ + +[invalid_CDScoo] +file = invalid_CDScoo.bed +title = invalid CDS coordinate in first line rgb is ignored +color = bed_rgb + +[spacer] + +[invalid_CDScoo2] +file = invalid_CDScoo2.bed +title = invalid CDS coordinate in not first line rgb can be used +color = bed_rgb +height = 2 + +[spacer] + +[invalid_CDScoo3] +file = invalid_CDScoo3.bed +title = invalid CDS coordinate in not first line bed12 can be used +color = bed_rgb +style = UCSC +height = 2 diff --git a/pygenometracks/tests/test_data/invalid_CDScoo2.bed b/pygenometracks/tests/test_data/invalid_CDScoo2.bed new file mode 100644 index 00000000..86248f5a --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_CDScoo2.bed @@ -0,0 +1,3 @@ +chrX 16000 18000 pos 0 + 17000 17500 255 +chrX 20000 21000 neg_invalidCDSstart 0 - a 20500 255,0,0 +chrX 22000 23400 no_strand_invalidCDSend 0 . 22000 b 0,255,0 \ No newline at end of file diff --git a/pygenometracks/tests/test_data/invalid_CDScoo3.bed b/pygenometracks/tests/test_data/invalid_CDScoo3.bed new file mode 100644 index 00000000..bd99b3a1 --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_CDScoo3.bed @@ -0,0 +1,5 @@ +chrX 18879 19093 CR40469 0 + 19093 19093 0 1 214, 0, +chrX 18879 19093 CR40469_invalidCDSstart 0 + a 19093 0 1 214, 0, +chrX 18879 19093 CR40469_invalidCDSend 0 + 19093 b 0 1 214, 0, +chrX 20756 23101 CG17636 0 - 20850 22441 0 4 1040,765,142,89, 0,1125,1985,2256, +chrX 20756 23101 CG17636_invalidCDSend 0 - 20850 b 0 4 1040,765,142,89, 0,1125,1985,2256, diff --git a/pygenometracks/tests/test_data/invalid_bedgraph.bdg b/pygenometracks/tests/test_data/invalid_bedgraph.bdg new file mode 100644 index 00000000..182d4425 --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_bedgraph.bdg @@ -0,0 +1,10 @@ +browser position chrX:2000000-3500000 +browser hide all +browser pack refGene encodeRegions +browser full altGraph +# 300 base wide bar graph, autoScale is on by default == graphing +# limits will dynamically change to always show full range of data +# in viewing window, priority = 20 positions this as the second graph +# Note, zero-relative, half-open coordinate system in use for bedGraph format +track type=bedGraph name="BedGraph Format" description="BedGraph format" visibility=full color=200,100,0 altColor=0,100,200 priority=20 +chrX diff --git a/pygenometracks/tests/test_data/invalid_bedgraph2.bdg b/pygenometracks/tests/test_data/invalid_bedgraph2.bdg new file mode 100644 index 00000000..2af6fa9d --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_bedgraph2.bdg @@ -0,0 +1,10 @@ +browser position chrX:2000000-3500000 +browser hide all +browser pack refGene encodeRegions +browser full altGraph +# 300 base wide bar graph, autoScale is on by default == graphing +# limits will dynamically change to always show full range of data +# in viewing window, priority = 20 positions this as the second graph +# Note, zero-relative, half-open coordinate system in use for bedGraph format +track type=bedGraph name="BedGraph Format" description="BedGraph format" visibility=full color=200,100,0 altColor=0,100,200 priority=20 +chrX a 3000000 diff --git a/pygenometracks/tests/test_data/invalid_bedgraph3.bdg b/pygenometracks/tests/test_data/invalid_bedgraph3.bdg new file mode 100644 index 00000000..419d93df --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_bedgraph3.bdg @@ -0,0 +1,10 @@ +browser position chrX:2000000-3500000 +browser hide all +browser pack refGene encodeRegions +browser full altGraph +# 300 base wide bar graph, autoScale is on by default == graphing +# limits will dynamically change to always show full range of data +# in viewing window, priority = 20 positions this as the second graph +# Note, zero-relative, half-open coordinate system in use for bedGraph format +track type=bedGraph name="BedGraph Format" description="BedGraph format" visibility=full color=200,100,0 altColor=0,100,200 priority=20 +chrX 2000000 3a00000 diff --git a/pygenometracks/tests/test_data/invalid_blockCount.bed b/pygenometracks/tests/test_data/invalid_blockCount.bed new file mode 100644 index 00000000..726ef69a --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_blockCount.bed @@ -0,0 +1,3 @@ +chrX 16000 18000 pos 0 + 17000 17500 255 a +chrX 20000 21000 neg 0 - 20200 20500 255,0,0 2 +chrX 22000 23400 no_strand 0 . 22000 23400 0,255,0 3 \ No newline at end of file diff --git a/pygenometracks/tests/test_data/invalid_blockCount.ini b/pygenometracks/tests/test_data/invalid_blockCount.ini new file mode 100644 index 00000000..8d6c0d2b --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_blockCount.ini @@ -0,0 +1,13 @@ + +[invalid_blockCount] +file = invalid_blockCount.bed +title = invalid block count in first line +color = bed_rgb + +[spacer] + +[invalid_blockCount] +file = invalid_blockCount2.bed +title = invalid block count in not first line -> bedtools raised an error +style = UCSC +height = 2 diff --git a/pygenometracks/tests/test_data/invalid_blockCount2.bed b/pygenometracks/tests/test_data/invalid_blockCount2.bed new file mode 100644 index 00000000..ded9fdb4 --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_blockCount2.bed @@ -0,0 +1,3 @@ +chrX 18879 19093 CR40469 0 + 19093 19093 0 1 214, 0, +chrX 20756 23101 CG17636 0 - 20850 22441 0 4 1040,765,142,89, 0,1125,1985,2256, +chrX 20756 23101 CG17636_wrongBlockCount 0 - 20850 22441 0 a 1040,765,142,89, 0,1125,1985,2256, diff --git a/pygenometracks/tests/test_data/invalid_blocks.bed b/pygenometracks/tests/test_data/invalid_blocks.bed new file mode 100644 index 00000000..ad8c0c18 --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_blocks.bed @@ -0,0 +1,2 @@ +chrX 18879 19093 CR40469 0 + 19093 19093 0 1 a, 0, +chrX 20756 23101 CG17636 0 - 20850 22441 0 4 1040,765,142,89, 0,1125,1985,2256, diff --git a/pygenometracks/tests/test_data/invalid_blocks.ini b/pygenometracks/tests/test_data/invalid_blocks.ini new file mode 100644 index 00000000..354308fb --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_blocks.ini @@ -0,0 +1,13 @@ + +[invalid_blocks] +file = invalid_blocks.bed +title = block_length is not integer in first line, block info is ignored +style = UCSC + +[spacer] + +[invalid_blocks2] +file = invalid_blocks2.bed +title = block_length is not integer in not first line blocks are used +style = UCSC +height = 4 diff --git a/pygenometracks/tests/test_data/invalid_blocks2.bed b/pygenometracks/tests/test_data/invalid_blocks2.bed new file mode 100644 index 00000000..d0dd96e0 --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_blocks2.bed @@ -0,0 +1,4 @@ +chrX 18879 19093 CR40469 0 + 19093 19093 0 1 214, 0, +chrX 20756 23101 CG17636 0 - 20850 22441 0 4 1040,765,142,89, 0,1125,1985,2256, +chrX 20756 23101 CG17636_invalid_block_start 0 - 20850 22441 0 4 1040,765,142,89, a,1125,1985,2256, +chrX 20756 23101 CG17636_invalid_block_length 0 - 20850 22441 0 4 1040,765,142,a, 0,1125,1985,2256, diff --git a/pygenometracks/tests/test_data/invalid_blocks3.bed b/pygenometracks/tests/test_data/invalid_blocks3.bed new file mode 100644 index 00000000..79819f3c --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_blocks3.bed @@ -0,0 +1,2 @@ +chrX 18879 19093 CR40469 0 + 19093 19093 0 1 214, 0, +chrX 20756 23101 CG17636_block_count_inconsistent 0 - 20850 22441 0 4 1040,765,142, 0,1125,1985, diff --git a/pygenometracks/tests/test_data/invalid_blocks4.bed b/pygenometracks/tests/test_data/invalid_blocks4.bed new file mode 100644 index 00000000..e21c90cf --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_blocks4.bed @@ -0,0 +1,2 @@ +chrX 18879 19093 CR40469 0 + 19093 19093 0 1 214, 0, +chrX 20756 23101 CG17636_inconsistent_block_number 0 - 20850 22441 0 4 1040,765,142, 0,1125,1985,2256, diff --git a/pygenometracks/tests/test_data/invalid_rgb.bed b/pygenometracks/tests/test_data/invalid_rgb.bed new file mode 100644 index 00000000..ff83451b --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_rgb.bed @@ -0,0 +1,4 @@ +chr1 0 100 pos 0 + 0 0 255 +chr1 200 220 neg1 0 - 200 200 r,g,b +chr1 280 300 neg2 0 - 200 200 255,0 +chr1 350 400 no_strand 0 . 350 350 255,0,0 \ No newline at end of file diff --git a/pygenometracks/tests/test_data/invalid_rgb.ini b/pygenometracks/tests/test_data/invalid_rgb.ini new file mode 100644 index 00000000..a92d2ee1 --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_rgb.ini @@ -0,0 +1,10 @@ + +[invalid_rgb] +file = invalid_rgb.bed +title = first line valid but neg invalid +color = bed_rgb + +[invalid_rgb2] +file = invalid_rgb2.bed +title = first line invalid +color = bed_rgb diff --git a/pygenometracks/tests/test_data/invalid_rgb2.bed b/pygenometracks/tests/test_data/invalid_rgb2.bed new file mode 100644 index 00000000..206c2c9f --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_rgb2.bed @@ -0,0 +1,3 @@ +chr1 0 100 pos 0 + 0 0 r,g,b +chr1 200 300 neg 0 - 200 200 255,0,0 +chr1 350 400 no_strand 0 . 350 350 0,255,0 \ No newline at end of file diff --git a/pygenometracks/tests/test_data/invalid_score.bed b/pygenometracks/tests/test_data/invalid_score.bed new file mode 100644 index 00000000..7ac7dfc7 --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_score.bed @@ -0,0 +1,3 @@ +chrX 16000 18000 pos a + 17000 17500 255 +chrX 20000 21000 neg 0 - 20200 20500 255,0,0 +chrX 22000 23400 no_strand 0 . 22000 23400 0,255,0 \ No newline at end of file diff --git a/pygenometracks/tests/test_data/invalid_score.ini b/pygenometracks/tests/test_data/invalid_score.ini new file mode 100644 index 00000000..8736a385 --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_score.ini @@ -0,0 +1,13 @@ + +[invalid_score] +file = invalid_score.bed +title = invalid score in first line strand and rgb is ignored +color = bed_rgb + +[spacer] + +[invalid_score2] +file = invalid_score2.bed +title = invalid score in not first line strand and rgb can be used +color = bed_rgb +height = 2 diff --git a/pygenometracks/tests/test_data/invalid_score2.bed b/pygenometracks/tests/test_data/invalid_score2.bed new file mode 100644 index 00000000..2e4767d8 --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_score2.bed @@ -0,0 +1,3 @@ +chrX 16000 18000 pos 0 + 17000 17500 255 +chrX 20000 21000 neg_invalid_score a - 20200 20500 255,0,0 +chrX 22000 23400 no_strand 0 . 22000 23400 0,255,0 \ No newline at end of file diff --git a/pygenometracks/tests/test_data/invalid_strand.bed b/pygenometracks/tests/test_data/invalid_strand.bed new file mode 100644 index 00000000..d70c38b9 --- /dev/null +++ b/pygenometracks/tests/test_data/invalid_strand.bed @@ -0,0 +1,3 @@ +chr1 0 100 pos 0 + +chr1 200 300 neg 0 - +chr1 350 400 no_strand 0 * diff --git a/pygenometracks/tests/test_data/log1p_grid.ini b/pygenometracks/tests/test_data/log1p_grid.ini new file mode 100644 index 00000000..b859b8f4 --- /dev/null +++ b/pygenometracks/tests/test_data/log1p_grid.ini @@ -0,0 +1,57 @@ + +[test bigwig] +file = bigwig_chrx_2e6_5e6.bw +color = red +height = 5 +transform = no +title = bigwig transform = no +[test bigwig] +file = bigwig_chrx_2e6_5e6.bw +color = red +height = 5 +transform = no +orientation = inverted +grid = true +title = bigwig transform = no orientation = inverted grid = true + + +[spacer] + +[test bigwig log] +file = bigwig_chrx_2e6_5e6.bw +color = red +height = 5 +transform = log1p +title = bigwig transform = log1p +[test bigwig log] +file = bigwig_chrx_2e6_5e6.bw +color = red +height = 5 +transform = log1p +orientation = inverted +grid = true +title = bigwig transform = log1p orientation = inverted grid = true + +[spacer] + +[test bigwig log] +file = bigwig_chrx_2e6_5e6.bw +color = red +min_value = 0 +height = 5 +transform = log1p +title = bigwig transform = log1p min_value = 0 y_axis_values = original +y_axis_values = original + +[test bigwig log] +file = bigwig_chrx_2e6_5e6.bw +color = red +min_value = 0 +height = 5 +transform = log1p +orientation = inverted +grid = true +title = bigwig transform = log1p min_value = 0 y_axis_values = original orientation = inverted grid = true +y_axis_values = original + +[x-axis] diff --git a/pygenometracks/tests/test_data/log_grid.ini b/pygenometracks/tests/test_data/log_grid.ini new file mode 100644 index 00000000..2ce8fb31 --- /dev/null +++ b/pygenometracks/tests/test_data/log_grid.ini @@ -0,0 +1,76 @@ + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = blue +height = 5 +grid = true +title = bedgraph color = blue transform = no grid=true +transform = no + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = blue +height = 5 +grid = true +title = bedgraph color = blue transform = log grid=true +transform = log + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = red +height = 5 +grid = true +title = bedgraph color = red transform = log min_value = 1 grid=true +min_value = 1 +transform = log + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = green +height = 5 +grid = true +title = bedgraph color = green transform = log log_pseudocount = 2 min_value = 0 grid=true +transform = log +log_pseudocount = 2 +min_value = 0 + +[test bedgraph with operation] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = green +height = 5 +grid = true +title = bedgraph color = green operation = log(2+file) min_value = 0.7 grid=true +operation = log(2+file) +min_value = 0.7 + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = black +height = 5 +grid = true +title = bedgraph color = black transform = log2 log_pseudocount = 1 min_value = 0 grid=true +transform = log2 +log_pseudocount = 1 +min_value = 0 + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = black +height = 5 +grid = true +title = bedgraph color = black operation = log2(1+file) min_value = 0 grid=true +operation = log2(1+file) +min_value = 0 + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = black +height = 5 +grid = true +title = bedgraph color = black transform = log2 log_pseudocount = 1 min_value = 0 y_axis_values = original grid=true +transform = log2 +log_pseudocount = 1 +min_value = 0 +y_axis_values = original + +[x-axis] diff --git a/pygenometracks/tests/test_data/log_more.ini b/pygenometracks/tests/test_data/log_more.ini new file mode 100644 index 00000000..e7276b7f --- /dev/null +++ b/pygenometracks/tests/test_data/log_more.ini @@ -0,0 +1,33 @@ + +[x-axis] + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = blue +height = 5 +title = bedgraph color = blue transform = log +transform = log + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = blue +height = 5 +title = bedgraph color = blue transform = log y_axis_values = original +transform = log +y_axis_values = original + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = blue +height = 5 +title = bedgraph color = blue transform = log10 y_axis_values = original +transform = log10 +y_axis_values = original + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = blue +height = 5 +title = bedgraph color = blue transform = -log y_axis_values = original +transform = -log +y_axis_values = original diff --git a/pygenometracks/tests/test_data/log_neg.ini b/pygenometracks/tests/test_data/log_neg.ini deleted file mode 100644 index 20448ba7..00000000 --- a/pygenometracks/tests/test_data/log_neg.ini +++ /dev/null @@ -1,7 +0,0 @@ - -[test bigwig] -file = bigwig_chrx_2e6_5e6.bw -color = red -height = 5 -transform = log -title = bigwig transform = log diff --git a/pygenometracks/tests/test_data/master_arcs_no_score.png b/pygenometracks/tests/test_data/master_arcs_no_score.png new file mode 100644 index 00000000..6a7091da Binary files /dev/null and b/pygenometracks/tests/test_data/master_arcs_no_score.png differ diff --git a/pygenometracks/tests/test_data/master_arcs_use_middle.png b/pygenometracks/tests/test_data/master_arcs_use_middle.png new file mode 100644 index 00000000..5e9f6179 Binary files /dev/null and b/pygenometracks/tests/test_data/master_arcs_use_middle.png differ diff --git a/pygenometracks/tests/test_data/master_bed_and_gtf.png b/pygenometracks/tests/test_data/master_bed_and_gtf.png index 3173d7dd..65332e13 100644 Binary files a/pygenometracks/tests/test_data/master_bed_and_gtf.png and b/pygenometracks/tests/test_data/master_bed_and_gtf.png differ diff --git a/pygenometracks/tests/test_data/master_bed_colormap_genes.png b/pygenometracks/tests/test_data/master_bed_colormap_genes.png index 51b2f502..c40d4560 100644 Binary files a/pygenometracks/tests/test_data/master_bed_colormap_genes.png and b/pygenometracks/tests/test_data/master_bed_colormap_genes.png differ diff --git a/pygenometracks/tests/test_data/master_bed_shuffle_chr1-0-500000.png b/pygenometracks/tests/test_data/master_bed_shuffle_chr1-0-500000.png new file mode 100644 index 00000000..13d1580c Binary files /dev/null and b/pygenometracks/tests/test_data/master_bed_shuffle_chr1-0-500000.png differ diff --git a/pygenometracks/tests/test_data/master_bed_shuffle_chrX-2500000-2600000.png b/pygenometracks/tests/test_data/master_bed_shuffle_chrX-2500000-2600000.png new file mode 100644 index 00000000..d817e2c6 Binary files /dev/null and b/pygenometracks/tests/test_data/master_bed_shuffle_chrX-2500000-2600000.png differ diff --git a/pygenometracks/tests/test_data/master_bed_shuffle_chrY-0-1000000.png b/pygenometracks/tests/test_data/master_bed_shuffle_chrY-0-1000000.png new file mode 100644 index 00000000..185448a3 Binary files /dev/null and b/pygenometracks/tests/test_data/master_bed_shuffle_chrY-0-1000000.png differ diff --git a/pygenometracks/tests/test_data/master_bed_vlines_X-3000000-3300000.png b/pygenometracks/tests/test_data/master_bed_vlines_X-3000000-3300000.png new file mode 100644 index 00000000..e416cf35 Binary files /dev/null and b/pygenometracks/tests/test_data/master_bed_vlines_X-3000000-3300000.png differ diff --git a/pygenometracks/tests/test_data/master_bed_vlines_fakeChr-0-100.png b/pygenometracks/tests/test_data/master_bed_vlines_fakeChr-0-100.png new file mode 100644 index 00000000..949e8c04 Binary files /dev/null and b/pygenometracks/tests/test_data/master_bed_vlines_fakeChr-0-100.png differ diff --git a/pygenometracks/tests/test_data/master_bedgraph_useMid.png b/pygenometracks/tests/test_data/master_bedgraph_useMid.png deleted file mode 100644 index d8c3149f..00000000 Binary files a/pygenometracks/tests/test_data/master_bedgraph_useMid.png and /dev/null differ diff --git a/pygenometracks/tests/test_data/master_bedgraph_useMid_chr2-73800000-75744000.png b/pygenometracks/tests/test_data/master_bedgraph_useMid_chr2-73800000-75744000.png new file mode 100644 index 00000000..e4d331ba Binary files /dev/null and b/pygenometracks/tests/test_data/master_bedgraph_useMid_chr2-73800000-75744000.png differ diff --git a/pygenometracks/tests/test_data/master_bedgraph_useMid_chr2-74000000-74800000.png b/pygenometracks/tests/test_data/master_bedgraph_useMid_chr2-74000000-74800000.png new file mode 100644 index 00000000..b8276f2e Binary files /dev/null and b/pygenometracks/tests/test_data/master_bedgraph_useMid_chr2-74000000-74800000.png differ diff --git a/pygenometracks/tests/test_data/master_bedgraph_useMid_zoom.png b/pygenometracks/tests/test_data/master_bedgraph_useMid_zoom.png deleted file mode 100644 index 9d296191..00000000 Binary files a/pygenometracks/tests/test_data/master_bedgraph_useMid_zoom.png and /dev/null differ diff --git a/pygenometracks/tests/test_data/master_bedgraph_withNA.png b/pygenometracks/tests/test_data/master_bedgraph_withNA.png new file mode 100644 index 00000000..4a6ff62e Binary files /dev/null and b/pygenometracks/tests/test_data/master_bedgraph_withNA.png differ diff --git a/pygenometracks/tests/test_data/master_different_UTR.png b/pygenometracks/tests/test_data/master_different_UTR.png new file mode 100644 index 00000000..42fc5f4a Binary files /dev/null and b/pygenometracks/tests/test_data/master_different_UTR.png differ diff --git a/pygenometracks/tests/test_data/master_empty2.png b/pygenometracks/tests/test_data/master_empty2.png new file mode 100644 index 00000000..1d9758d6 Binary files /dev/null and b/pygenometracks/tests/test_data/master_empty2.png differ diff --git a/pygenometracks/tests/test_data/master_example_bigwig.png b/pygenometracks/tests/test_data/master_example_bigwig.png new file mode 100644 index 00000000..f8a518c0 Binary files /dev/null and b/pygenometracks/tests/test_data/master_example_bigwig.png differ diff --git a/pygenometracks/tests/test_data/master_grid.png b/pygenometracks/tests/test_data/master_grid.png new file mode 100644 index 00000000..19260807 Binary files /dev/null and b/pygenometracks/tests/test_data/master_grid.png differ diff --git a/pygenometracks/tests/test_data/master_hic_small_test_2.png b/pygenometracks/tests/test_data/master_hic_small_test_2.png new file mode 100644 index 00000000..b9c2974f Binary files /dev/null and b/pygenometracks/tests/test_data/master_hic_small_test_2.png differ diff --git a/pygenometracks/tests/test_data/master_hic_small_test_3.png b/pygenometracks/tests/test_data/master_hic_small_test_3.png new file mode 100644 index 00000000..2c973a9d Binary files /dev/null and b/pygenometracks/tests/test_data/master_hic_small_test_3.png differ diff --git a/pygenometracks/tests/test_data/master_hic_small_test_above_chrY.png b/pygenometracks/tests/test_data/master_hic_small_test_above_chrY.png new file mode 100644 index 00000000..2db8337b Binary files /dev/null and b/pygenometracks/tests/test_data/master_hic_small_test_above_chrY.png differ diff --git a/pygenometracks/tests/test_data/master_hic_small_test_small_region.png b/pygenometracks/tests/test_data/master_hic_small_test_small_region.png new file mode 100644 index 00000000..a7753bea Binary files /dev/null and b/pygenometracks/tests/test_data/master_hic_small_test_small_region.png differ diff --git a/pygenometracks/tests/test_data/master_invalid_CDScoo.png b/pygenometracks/tests/test_data/master_invalid_CDScoo.png new file mode 100644 index 00000000..40643907 Binary files /dev/null and b/pygenometracks/tests/test_data/master_invalid_CDScoo.png differ diff --git a/pygenometracks/tests/test_data/master_invalid_blockCount.png b/pygenometracks/tests/test_data/master_invalid_blockCount.png new file mode 100644 index 00000000..d421cbc5 Binary files /dev/null and b/pygenometracks/tests/test_data/master_invalid_blockCount.png differ diff --git a/pygenometracks/tests/test_data/master_invalid_blocks.png b/pygenometracks/tests/test_data/master_invalid_blocks.png new file mode 100644 index 00000000..10db8046 Binary files /dev/null and b/pygenometracks/tests/test_data/master_invalid_blocks.png differ diff --git a/pygenometracks/tests/test_data/master_invalid_rgb.png b/pygenometracks/tests/test_data/master_invalid_rgb.png new file mode 100644 index 00000000..5b67b88c Binary files /dev/null and b/pygenometracks/tests/test_data/master_invalid_rgb.png differ diff --git a/pygenometracks/tests/test_data/master_invalid_score.png b/pygenometracks/tests/test_data/master_invalid_score.png new file mode 100644 index 00000000..2f23f25c Binary files /dev/null and b/pygenometracks/tests/test_data/master_invalid_score.png differ diff --git a/pygenometracks/tests/test_data/master_log1p_grid.png b/pygenometracks/tests/test_data/master_log1p_grid.png new file mode 100644 index 00000000..28aa06c4 Binary files /dev/null and b/pygenometracks/tests/test_data/master_log1p_grid.png differ diff --git a/pygenometracks/tests/test_data/master_log_grid.png b/pygenometracks/tests/test_data/master_log_grid.png new file mode 100644 index 00000000..bca5e22d Binary files /dev/null and b/pygenometracks/tests/test_data/master_log_grid.png differ diff --git a/pygenometracks/tests/test_data/master_log_more.png b/pygenometracks/tests/test_data/master_log_more.png new file mode 100644 index 00000000..e68758ae Binary files /dev/null and b/pygenometracks/tests/test_data/master_log_more.png differ diff --git a/pygenometracks/tests/test_data/master_mcool.png b/pygenometracks/tests/test_data/master_mcool.png new file mode 100644 index 00000000..4d7c7a7a Binary files /dev/null and b/pygenometracks/tests/test_data/master_mcool.png differ diff --git a/pygenometracks/tests/test_data/master_negative.png b/pygenometracks/tests/test_data/master_negative.png new file mode 100644 index 00000000..c7f1bf79 Binary files /dev/null and b/pygenometracks/tests/test_data/master_negative.png differ diff --git a/pygenometracks/tests/test_data/master_operation_2L.png b/pygenometracks/tests/test_data/master_operation_2L.png new file mode 100644 index 00000000..34548e11 Binary files /dev/null and b/pygenometracks/tests/test_data/master_operation_2L.png differ diff --git a/pygenometracks/tests/test_data/master_operation_fakeChr.png b/pygenometracks/tests/test_data/master_operation_fakeChr.png new file mode 100644 index 00000000..0bd05d5c Binary files /dev/null and b/pygenometracks/tests/test_data/master_operation_fakeChr.png differ diff --git a/pygenometracks/tests/test_data/master_plot.png b/pygenometracks/tests/test_data/master_plot.png index fceda144..c7fa9930 100644 Binary files a/pygenometracks/tests/test_data/master_plot.png and b/pygenometracks/tests/test_data/master_plot.png differ diff --git a/pygenometracks/tests/test_data/master_plot_2.png b/pygenometracks/tests/test_data/master_plot_2.png index 75625ddd..325062c3 100644 Binary files a/pygenometracks/tests/test_data/master_plot_2.png and b/pygenometracks/tests/test_data/master_plot_2.png differ diff --git a/pygenometracks/tests/test_data/master_plot_3.png b/pygenometracks/tests/test_data/master_plot_3.png index 023f1dcb..366ffaac 100644 Binary files a/pygenometracks/tests/test_data/master_plot_3.png and b/pygenometracks/tests/test_data/master_plot_3.png differ diff --git a/pygenometracks/tests/test_data/master_plot_dec.png b/pygenometracks/tests/test_data/master_plot_dec.png index 81620388..6a3781ae 100644 Binary files a/pygenometracks/tests/test_data/master_plot_dec.png and b/pygenometracks/tests/test_data/master_plot_dec.png differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_one_interaction_diag_chrY-0-1000000.png b/pygenometracks/tests/test_data/master_plot_hic_one_interaction_diag_chrY-0-1000000.png new file mode 100644 index 00000000..16a7cd8b Binary files /dev/null and b/pygenometracks/tests/test_data/master_plot_hic_one_interaction_diag_chrY-0-1000000.png differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_one_interaction_withBED_chr1-0-500000.png b/pygenometracks/tests/test_data/master_plot_hic_one_interaction_withBED_chr1-0-500000.png new file mode 100644 index 00000000..ac8427c0 Binary files /dev/null and b/pygenometracks/tests/test_data/master_plot_hic_one_interaction_withBED_chr1-0-500000.png differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_one_interaction_withBED_chrX-2500000-2600000.png b/pygenometracks/tests/test_data/master_plot_hic_one_interaction_withBED_chrX-2500000-2600000.png new file mode 100644 index 00000000..53988da9 Binary files /dev/null and b/pygenometracks/tests/test_data/master_plot_hic_one_interaction_withBED_chrX-2500000-2600000.png differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_one_interaction_withBED_chrY-0-1000000.png b/pygenometracks/tests/test_data/master_plot_hic_one_interaction_withBED_chrY-0-1000000.png new file mode 100644 index 00000000..bd910ece Binary files /dev/null and b/pygenometracks/tests/test_data/master_plot_hic_one_interaction_withBED_chrY-0-1000000.png differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_one_interaction_withRegion_chrY-0-1000000.png b/pygenometracks/tests/test_data/master_plot_hic_one_interaction_withRegion_chrY-0-1000000.png new file mode 100644 index 00000000..40498368 Binary files /dev/null and b/pygenometracks/tests/test_data/master_plot_hic_one_interaction_withRegion_chrY-0-1000000.png differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_rasterize_height.pdf b/pygenometracks/tests/test_data/master_plot_hic_rasterize_height_X-2500000-2600000.pdf similarity index 99% rename from pygenometracks/tests/test_data/master_plot_hic_rasterize_height.pdf rename to pygenometracks/tests/test_data/master_plot_hic_rasterize_height_X-2500000-2600000.pdf index 41562985..1b15f730 100644 Binary files a/pygenometracks/tests/test_data/master_plot_hic_rasterize_height.pdf and b/pygenometracks/tests/test_data/master_plot_hic_rasterize_height_X-2500000-2600000.pdf differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_rasterize_height_Y-0-1000000.pdf b/pygenometracks/tests/test_data/master_plot_hic_rasterize_height_Y-0-1000000.pdf new file mode 100644 index 00000000..7734e447 Binary files /dev/null and b/pygenometracks/tests/test_data/master_plot_hic_rasterize_height_Y-0-1000000.pdf differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_rasterize_height_pdf.png b/pygenometracks/tests/test_data/master_plot_hic_rasterize_height_pdf.png deleted file mode 100644 index 64effd42..00000000 Binary files a/pygenometracks/tests/test_data/master_plot_hic_rasterize_height_pdf.png and /dev/null differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_small_test.png b/pygenometracks/tests/test_data/master_plot_hic_small_test.png new file mode 100644 index 00000000..53dcfcf4 Binary files /dev/null and b/pygenometracks/tests/test_data/master_plot_hic_small_test.png differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_small_test_chr1-0-500000.png b/pygenometracks/tests/test_data/master_plot_hic_small_test_chr1-0-500000.png new file mode 100644 index 00000000..d15892f0 Binary files /dev/null and b/pygenometracks/tests/test_data/master_plot_hic_small_test_chr1-0-500000.png differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_small_test_chrM.png b/pygenometracks/tests/test_data/master_plot_hic_small_test_chrM.png new file mode 100644 index 00000000..b705d689 Binary files /dev/null and b/pygenometracks/tests/test_data/master_plot_hic_small_test_chrM.png differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_small_test_chrX-2500000-2600000.png b/pygenometracks/tests/test_data/master_plot_hic_small_test_chrX-2500000-2600000.png new file mode 100644 index 00000000..fea77fc9 Binary files /dev/null and b/pygenometracks/tests/test_data/master_plot_hic_small_test_chrX-2500000-2600000.png differ diff --git a/pygenometracks/tests/test_data/master_plot_hic_small_test_chrY-0-1000000.png b/pygenometracks/tests/test_data/master_plot_hic_small_test_chrY-0-1000000.png new file mode 100644 index 00000000..a1d1d5bc Binary files /dev/null and b/pygenometracks/tests/test_data/master_plot_hic_small_test_chrY-0-1000000.png differ diff --git a/pygenometracks/tests/test_data/master_strange_strand.png b/pygenometracks/tests/test_data/master_strange_strand.png new file mode 100644 index 00000000..1f315391 Binary files /dev/null and b/pygenometracks/tests/test_data/master_strange_strand.png differ diff --git a/pygenometracks/tests/test_data/master_title_force_height.png b/pygenometracks/tests/test_data/master_title_force_height.png new file mode 100644 index 00000000..395be895 Binary files /dev/null and b/pygenometracks/tests/test_data/master_title_force_height.png differ diff --git a/pygenometracks/tests/test_data/master_tracks.ini b/pygenometracks/tests/test_data/master_tracks.ini index e5154b0b..bceaf9c8 100644 --- a/pygenometracks/tests/test_data/master_tracks.ini +++ b/pygenometracks/tests/test_data/master_tracks.ini @@ -13,8 +13,8 @@ height = 0.5 [Li_et_al_2015] file = pygenometracks/tests/test_data/Li_et_al_2015.h5 -title = Li_et_al_2015 -# The different options for color maps can be found here: https://matplotlib.org/users/colormaps.html +# The different options for color maps can be found here: +# https://matplotlib.org/users/colormaps.html # the default color map is RdYlBu_r (_r) stands for reverse # If you want your own colormap you can put the values of the color you want # For example, colormap = ['blue', 'yellow', 'red'] @@ -24,7 +24,8 @@ title = Li_et_al_2015 # If it is more than 125% of the plotted region, it will # be adjsted to this maximum value. depth = 100000 -# height of track (in cm) can be given. Otherwise, the height is computed such that the proportions of the +# height of track (in cm) can be given. +# Otherwise, the height is computed such that the proportions of the # hic matrix are kept (e.g. the image does not appear shrink or extended) # height = 10 # min_value and max_value refer to the contacts in the matrix. @@ -37,8 +38,6 @@ transform = log1p # the default is to extend neighboring bins to # obtain an aesthetically pleasant output show_masked_bins = false -# if you want to plot the track upside-down: -# orientation = inverted # optional if the values in the matrix need to be scaled the # following parameter can be used. This is useful to plot multiple hic-matrices on the same scale # scale_factor = 1 @@ -56,19 +55,23 @@ title = bigwig_chrx_2e6_5e6 height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes color = #666666 +# To use a different color for negative values +#negative_color = red # To use transparency, you can use alpha # default is 1 # alpha = 0.5 # the default for min_value and max_value is 'auto' which means that the scale will go -# from the minimum value found in the region plotted to the maximum value found. +# roughly from the minimum value found in the region plotted to the maximum value found. min_value = 0 #max_value = auto -# The number of bins takes the region to be plotted and divides it into the number of bins specified +# The number of bins takes the region to be plotted and divides it +# into the number of bins specified # Then, at each bin the bigwig mean value is computed and plotted. # A lower number of bins produces a coarser tracks number_of_bins = 700 @@ -111,6 +114,8 @@ show_data_range = true # gives the transformed values, if you prefer to see # the original values: #y_axis_values = original +# If you want to have a grid on the y-axis +#grid = true file_type = bigwig [tad_classification] @@ -122,8 +127,9 @@ title = tad_classification height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes # If the bed file contains the exon @@ -131,8 +137,8 @@ height = 2 # a region **with direction** is plotted. # If the bed file contains a column for color (column 9), then this color can be used by # setting: -# color = bed_rgb -#if color is a valid colormap name (like RbBlGn), then the score is mapped +#color = bed_rgb +# if color is a valid colormap name (like RbBlGn), then the score (column 5) is mapped # to the colormap. # In this case, the the min_value and max_value for the score can be provided, otherwise # the maximum score and minimum score found are used. @@ -141,8 +147,6 @@ height = 2 #max_value=100 # If the color is simply a color name, then this color is used and the score is not considered. color = darkblue -# height of track in cm -height = 5 # whether printing the labels labels = false # optional: @@ -154,21 +158,24 @@ fontsize = 10 # optional: line_width #line_width = 0.5 # the display parameter defines how the bed file is plotted. -# The options are ['collapsed', 'interleaved', 'triangles'] These options asume that the regions do not overlap. +# Default is 'stacked' where regions are plotted on different lines so +# we can see all regions and all labels. +# The other options are ['collapsed', 'interleaved', 'triangles'] +# These options assume that the regions do not overlap. # `collapsed`: The bed regions are plotted one after the other in one line. # `interleaved`: The bed regions are plotted in two lines, first up, then down, then up etc. -# if display is not given, then each region is plotted using the gene style # optional, default is black. To remove the border, simply set 'border_color' to none # Not used in tssarrow style #border_color = black -# style to plot the genes when they have exon information +# style to plot the genes when the display is not triangles #style = UCSC #style = flybase #style = tssarrow # maximum number of gene rows to be plotted. This # field is useful to limit large number of close genes # to be printed over many rows. When several images want -# to be combined this must be set to get equal size, otherwise, on each image the height of each gene changes +# to be combined this must be set to get equal size +# otherwise, on each image the height of each gene changes #gene_rows = 10 # by default the ymax is the number of # rows occupied by the genes in the region plotted. However, @@ -198,9 +205,6 @@ fontsize = 10 # If you want that the tip of the arrow correspond to # the extremity of the interval use: # arrowhead_included = true -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale -#overlay_previous = yes # optional. If not given is guessed from the file ending. file_type = bed @@ -213,8 +217,9 @@ title = epilog.qcat height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes # The categories file should contain the color information for each category id diff --git a/pygenometracks/tests/test_data/matrix.mcool b/pygenometracks/tests/test_data/matrix.mcool new file mode 100644 index 00000000..05336183 Binary files /dev/null and b/pygenometracks/tests/test_data/matrix.mcool differ diff --git a/pygenometracks/tests/test_data/mcool.ini b/pygenometracks/tests/test_data/mcool.ini new file mode 100644 index 00000000..ec3ddf2e --- /dev/null +++ b/pygenometracks/tests/test_data/mcool.ini @@ -0,0 +1,22 @@ + +[x-axis] + +[mcool1] +file = matrix.mcool::/0 +depth = 1000000 +file_type = hic_matrix + +[mcool2] +file = matrix.mcool::/1 +depth = 1000000 +file_type = hic_matrix + +[mcool3] +file = matrix.mcool::/2 +depth = 1000000 +file_type = hic_matrix + +[mcool4] +file = matrix.mcool::/4 +depth = 1000000 +file_type = hic_matrix diff --git a/pygenometracks/tests/test_data/one_interaction_4chr.cool b/pygenometracks/tests/test_data/one_interaction_4chr.cool new file mode 100644 index 00000000..6dc4b2b8 Binary files /dev/null and b/pygenometracks/tests/test_data/one_interaction_4chr.cool differ diff --git a/pygenometracks/tests/test_data/one_interaction_4chr.h5 b/pygenometracks/tests/test_data/one_interaction_4chr.h5 new file mode 100644 index 00000000..67fe1ce9 Binary files /dev/null and b/pygenometracks/tests/test_data/one_interaction_4chr.h5 differ diff --git a/pygenometracks/tests/test_data/one_interaction_diag_4chr.h5 b/pygenometracks/tests/test_data/one_interaction_diag_4chr.h5 new file mode 100644 index 00000000..4a90eb93 Binary files /dev/null and b/pygenometracks/tests/test_data/one_interaction_diag_4chr.h5 differ diff --git a/pygenometracks/tests/test_data/operation_bdg.ini b/pygenometracks/tests/test_data/operation_bdg.ini index 2fc9bc25..eafac751 100644 --- a/pygenometracks/tests/test_data/operation_bdg.ini +++ b/pygenometracks/tests/test_data/operation_bdg.ini @@ -48,7 +48,7 @@ height = 0.5 [test op2] file = bedgraph2_X_2.5e6_3.5e6.bdg -second_file = bedgraph_chrx_2e6_5e6.bg.bgz +second_file = bedgraph_chrx_2e6_5e6_2.bg.bgz color = red negative_color = blue height = 8 diff --git a/pygenometracks/tests/test_data/regions.bed b/pygenometracks/tests/test_data/regions.bed new file mode 100644 index 00000000..8836efc3 --- /dev/null +++ b/pygenometracks/tests/test_data/regions.bed @@ -0,0 +1,2 @@ +X 3120000 3150000 region1 +X 3130000 3140000 zoom diff --git a/pygenometracks/tests/test_data/regionsXfakeChr.bed b/pygenometracks/tests/test_data/regionsXfakeChr.bed new file mode 100644 index 00000000..7ab9f843 --- /dev/null +++ b/pygenometracks/tests/test_data/regionsXfakeChr.bed @@ -0,0 +1,2 @@ +X 3000000 3300000 +fakeChr 0 100 diff --git a/pygenometracks/tests/test_data/regions_XY.bed b/pygenometracks/tests/test_data/regions_XY.bed new file mode 100644 index 00000000..16267802 --- /dev/null +++ b/pygenometracks/tests/test_data/regions_XY.bed @@ -0,0 +1,2 @@ +X 2500000 2600000 +Y 0 1000000 diff --git a/pygenometracks/tests/test_data/regions_chr1XY.bed b/pygenometracks/tests/test_data/regions_chr1XY.bed new file mode 100644 index 00000000..a1f74c4b --- /dev/null +++ b/pygenometracks/tests/test_data/regions_chr1XY.bed @@ -0,0 +1,3 @@ +chr1 0 500000 +chrX 2500000 2600000 +chrY 0 1000000 diff --git a/pygenometracks/tests/test_data/regions_imbricated_chr2.bed b/pygenometracks/tests/test_data/regions_imbricated_chr2.bed new file mode 100644 index 00000000..adef7d87 --- /dev/null +++ b/pygenometracks/tests/test_data/regions_imbricated_chr2.bed @@ -0,0 +1,3 @@ +track type=bed name=regions_to_plot +chr2 73800000 75744000 +chr2 74000000 74800000 \ No newline at end of file diff --git a/pygenometracks/tests/test_data/small_test2.cool b/pygenometracks/tests/test_data/small_test2.cool new file mode 100644 index 00000000..ad78b9f7 Binary files /dev/null and b/pygenometracks/tests/test_data/small_test2.cool differ diff --git a/pygenometracks/tests/test_data/small_test3.cool b/pygenometracks/tests/test_data/small_test3.cool new file mode 100644 index 00000000..f9b07b89 Binary files /dev/null and b/pygenometracks/tests/test_data/small_test3.cool differ diff --git a/pygenometracks/tests/test_data/strange_strand.bed b/pygenometracks/tests/test_data/strange_strand.bed new file mode 100644 index 00000000..8307a4c2 --- /dev/null +++ b/pygenometracks/tests/test_data/strange_strand.bed @@ -0,0 +1,3 @@ +chr1 0 100 pos 0 1 +chr1 200 300 neg 0 -1 +chr1 350 400 no_strand 0 . diff --git a/pygenometracks/tests/test_data/strange_strand.ini b/pygenometracks/tests/test_data/strange_strand.ini new file mode 100644 index 00000000..ed988733 --- /dev/null +++ b/pygenometracks/tests/test_data/strange_strand.ini @@ -0,0 +1,3 @@ + +[strange_strand] +file = strange_strand.bed diff --git a/pygenometracks/tests/test_data/test_high_score.arcs b/pygenometracks/tests/test_data/test_high_score.arcs new file mode 100644 index 00000000..19044c75 --- /dev/null +++ b/pygenometracks/tests/test_data/test_high_score.arcs @@ -0,0 +1,3 @@ +chrX 3000000 3000001 chrX 3010000 3010001 100 +chrX 3030000 3030001 chrX 3080000 3080001 50 +chrX 3030000 3030001 chrX 3200000 3200001 2 diff --git a/pygenometracks/tests/test_data/test_noscore.arcs b/pygenometracks/tests/test_data/test_noscore.arcs new file mode 100644 index 00000000..6209ae7d --- /dev/null +++ b/pygenometracks/tests/test_data/test_noscore.arcs @@ -0,0 +1,3 @@ +chrX 3000000 3000001 chrX 3010000 3010001 +chrX 3030000 3030001 chrX 3080000 3080001 +chrX 3030000 3030001 chrX 3200000 3200001 diff --git a/pygenometracks/tests/test_data/test_wide.arcs b/pygenometracks/tests/test_data/test_wide.arcs new file mode 100644 index 00000000..196b3fdf --- /dev/null +++ b/pygenometracks/tests/test_data/test_wide.arcs @@ -0,0 +1,3 @@ +chrX 3000000 3005000 chrX 3010000 3018000 1 +chrX 3030000 3032000 chrX 3080000 3090000 0.5 +chrX 3030000 3040000 chrX 3200000 3280000 2 diff --git a/pygenometracks/tests/test_data/test_with_neg_values.bg.gz b/pygenometracks/tests/test_data/test_with_neg_values.bg.gz new file mode 100644 index 00000000..d7c8f1d4 Binary files /dev/null and b/pygenometracks/tests/test_data/test_with_neg_values.bg.gz differ diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/bed_as_gtf.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/bed_as_gtf.ini deleted file mode 100644 index dbfaf2d5..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/bed_as_gtf.ini +++ /dev/null @@ -1,7 +0,0 @@ - -[test bed] -file = ../dm3_genes.bed.gz -height = 10 -title = bed file -fontsize = 12 -file_type = gtf diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/empty.bed b/pygenometracks/tests/test_data/uncorrect_ini_files/empty.bed deleted file mode 100644 index e69de29b..00000000 diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/gtf_as_bed.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/gtf_as_bed.ini deleted file mode 100644 index 8d103b01..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/gtf_as_bed.ini +++ /dev/null @@ -1,7 +0,0 @@ - -[test gtf] -file = ../dm3_subset_BDGP5.78_gtf.dat -height = 10 -title = gtf from ensembl (with dat extension) -fontsize = 12 -file_type = bed diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_1.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_1.ini deleted file mode 100644 index 705f7e91..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_1.ini +++ /dev/null @@ -1,3 +0,0 @@ - -[vlines] -type = vlines diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_10.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_10.ini deleted file mode 100644 index e0c80190..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_10.ini +++ /dev/null @@ -1,4 +0,0 @@ - -[inexisting file] -file_type = bed -file = FileWhichDoesNotExists.txt diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_11.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_11.ini deleted file mode 100644 index 31f73d7e..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_11.ini +++ /dev/null @@ -1,3 +0,0 @@ - -[unguessable file] -file = FileWhichDoesNotExists.unknownextension diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_2.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_2.ini deleted file mode 100644 index dc92a629..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_2.ini +++ /dev/null @@ -1,3 +0,0 @@ - -[wrong file_type] -file_type = newFileTypeIJustInvented diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_3.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_3.ini deleted file mode 100644 index fbda0f37..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_3.ini +++ /dev/null @@ -1,3 +0,0 @@ - -[undetermined section] -title = I do not know what diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_4.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_4.ini deleted file mode 100644 index 35e687cd..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_4.ini +++ /dev/null @@ -1,3 +0,0 @@ - -[missing necessary option] -file_type = bed diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_5.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_5.ini deleted file mode 100644 index 2c3c1099..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_5.ini +++ /dev/null @@ -1,5 +0,0 @@ - -[problem with boolean] -file_type = bed -file = empty.bed -labels = 2 diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_6.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_6.ini deleted file mode 100644 index 2a56ccf5..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_6.ini +++ /dev/null @@ -1,5 +0,0 @@ - -[problem with float] -file_type = bed -file = empty.bed -max_value = a diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_7.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_7.ini deleted file mode 100644 index 6a7b1c52..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_7.ini +++ /dev/null @@ -1,5 +0,0 @@ - -[problem with float range] -file_type = bed -file = empty.bed -fontsize = -2 diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_8.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_8.ini deleted file mode 100644 index e707d4a2..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_8.ini +++ /dev/null @@ -1,5 +0,0 @@ - -[problem with integer] -file_type = bed -file = empty.bed -gene_rows = 1a2 diff --git a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_9.ini b/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_9.ini deleted file mode 100644 index e8b441fa..00000000 --- a/pygenometracks/tests/test_data/uncorrect_ini_files/test_tracks_9.ini +++ /dev/null @@ -1,5 +0,0 @@ - -[problem with integer range] -file_type = bed -file = empty.bed -gene_rows = -2 diff --git a/pygenometracks/tests/test_data/unsorted_bedgraph.bdg b/pygenometracks/tests/test_data/unsorted_bedgraph.bdg new file mode 100644 index 00000000..b58d9bed --- /dev/null +++ b/pygenometracks/tests/test_data/unsorted_bedgraph.bdg @@ -0,0 +1,11 @@ +browser position chrX:2000000-3500000 +browser hide all +browser pack refGene encodeRegions +browser full altGraph +# 300 base wide bar graph, autoScale is on by default == graphing +# limits will dynamically change to always show full range of data +# in viewing window, priority = 20 positions this as the second graph +# Note, zero-relative, half-open coordinate system in use for bedGraph format +track type=bedGraph name="BedGraph Format" description="BedGraph format" visibility=full color=200,100,0 altColor=0,100,200 priority=20 +chrX 3080750 4000800 2 +chrX 2000000 3000000 1 diff --git a/pygenometracks/tests/test_data/unsorted_bedgraph.ini b/pygenometracks/tests/test_data/unsorted_bedgraph.ini new file mode 100644 index 00000000..93e4a04a --- /dev/null +++ b/pygenometracks/tests/test_data/unsorted_bedgraph.ini @@ -0,0 +1,6 @@ + +[unsorted_bedgraph] +file = unsorted_bedgraph.bdg +height = 3 + +[x-axis] diff --git a/pygenometracks/tests/test_deprecation.py b/pygenometracks/tests/test_deprecation.py new file mode 100644 index 00000000..791fa22e --- /dev/null +++ b/pygenometracks/tests/test_deprecation.py @@ -0,0 +1,192 @@ +# -*- coding: utf-8 -*- +import matplotlib as mpl +from matplotlib.testing.compare import compare_images +from tempfile import NamedTemporaryFile +import os.path +import pygenometracks.plotTracks +mpl.use('agg') + +ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), + "test_data") + +with open(os.path.join(ROOT, "bed_and_gtf_tracks.ini"), 'r') as f: + with open(os.path.join(ROOT, "bed_and_gtf_tracks_dep.ini"), 'w') as fo: + flag = False + for line in f: + if 'dm3_subset_BDGP5.78.gtf.gz' in line: + flag = True + if 'file_type' in line and flag: + line = 'file_type = bed\n' + flag = False + fo.write(line) + +browser_tracks = """ +[test bigwig lines] +file = bigwig2_X_2.5e6_3.5e6.bw +color = gray +height = 2 +type = line +#title = orientation=inverted; show data range=no +title = orientation = inverted; show_data_range = false +orientation = inverted +show data range = no +max_value = 50 + +[test bigwig lines:0.2] +file = bigwig_chrx_2e6_5e6.bw +color = red +height = 2 +type = line:0.2 +title = type=line:0.2 + +[spacer] + +[test bigwig points] +file = bigwig_chrx_2e6_5e6.bw +color = black +height = 2 +min_value = 0 +max_value = 100 +type = points:0.5 +# title = type=point:0.5; min_value=0;max_value=100 +title = type = point:0.5; min_value = 0; max_value = 100 + +[spacer] + +[test bigwig nans to zeros] +file = bigwig_chrx_2e6_5e6.bw +color = red +height = 2 +nans to zeros = True +# title = nans to zeros =True +title = nans_to_zeros = true + +[spacer] + +[test bigwig mean] +file = bigwig2_X_2.5e6_3.5e6.bw +color = gray +height = 5 +# title = gray:summary method=mean; blue:summary method=max; red:summary method=min +title = gray:summary_method = mean; blue:summary_method = max; + red:summary_method = min +type = line +summary method = mean +max_value = 150 +min_value = -5 +show data range = no +number of bins = 300 + +[test bigwig max] +file = bigwig2_X_2.5e6_3.5e6.bw +#title = test +color = blue +type = line +summary method = max +max_value = 150 +min_value = -15 +show data range = no +overlay previous = share-y +number of bins = 300 + +[test bigwig min] +file = bigwig2_X_2.5e6_3.5e6.bw +color = red +type=line +summary method = min +max_value = 150 +min_value = -25 +overlay previous = share-y +number of bins = 300 + +[spacer] + +[x-axis] +""" +with open(os.path.join(ROOT, "bigwig_dep.ini"), 'w') as fh: + fh.write(browser_tracks) + + +browser_tracks_with_hic = """ +[hic matrix] +file = small_test2.cool +title = cool with few interactions show_masked_bins = false (default) +depth = 200000 +file_type = hic_matrix +boudaries_file = tad_classification.bed +height = 5 + +[spacer] + +[hic matrix] +file = small_test2.cool +title = cool with few interactions show_masked_bins = true +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = true + +[x-axis] +""" +with open(os.path.join(ROOT, "browser_tracks_hic_small_test_boundaries_file.ini"), 'w') as fh: + fh.write(browser_tracks_with_hic) + + +tolerance = 13 # default matplotlib pixed difference tolerance + + +def test_plot_tracks_bed_and_gtf_dep(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, 'bed_and_gtf_tracks_dep.ini') + region = "X:3000000-3300000" + expected_file = os.path.join(ROOT, 'master_bed_and_gtf.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + os.remove(ini_file) + + +def test_bigwig_track_dep(): + outfile = NamedTemporaryFile(suffix='.png', prefix='bigwig_test_', + delete=False) + ini_file = os.path.join(ROOT, "bigwig_dep.ini") + region = "X:2700000-3100000" + expected_file = os.path.join(ROOT, 'master_bigwig.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + os.remove(ini_file) + + +def test_plot_tracks_with_hic_small_file_boundaries(): + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + region = '1:0-200000' + expected_file = os.path.join(ROOT, 'master_plot_hic_small_test.png') + + ini_file = os.path.join(ROOT, 'browser_tracks_hic_small_test_boundaries_file.ini') + + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + os.remove(ini_file) diff --git a/pygenometracks/tests/test_epilogosTrack.py b/pygenometracks/tests/test_epilogosTrack.py index bd58c6ad..776eb41c 100644 --- a/pygenometracks/tests/test_epilogosTrack.py +++ b/pygenometracks/tests/test_epilogosTrack.py @@ -42,15 +42,16 @@ def test_epilogos_track(): + outfile = NamedTemporaryFile(suffix='.png', prefix='bedgraph_test_', + delete=False) + ini_file = os.path.join(ROOT, "epilogos.ini") region = "X:3100000-3150000" - outfile = NamedTemporaryFile(suffix='.png', prefix='bedgraph_test_', delete=False) - args = "--tracks {ini} --region {region} --trackLabelFraction 0.2 " \ - "--dpi 130 --outFileName {outfile}" \ - "".format(ini=os.path.join(ROOT, "epilogos.ini"), - outfile=outfile.name, region=region).split() + expected_file = os.path.join(ROOT, 'master_epilogos.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_epilogos.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res diff --git a/pygenometracks/tests/test_hiCMatrixTracks.py b/pygenometracks/tests/test_hiCMatrixTracks.py index f7008b74..1ab0c7e3 100644 --- a/pygenometracks/tests/test_hiCMatrixTracks.py +++ b/pygenometracks/tests/test_hiCMatrixTracks.py @@ -119,7 +119,7 @@ browser_tracks_with_hic = """ [hic matrix] -file = Li_et_al_2015.h5 +file = Li_et_al_2015.cool title = depth = 200000; transform = log1p; min_value = 5; height = 5 depth = 200000 min_value = 5 @@ -158,6 +158,35 @@ with open(os.path.join(ROOT, "browser_tracks_hic_rasterize_height.ini"), 'w') as fh: fh.write(browser_tracks_with_hic) +browser_tracks_with_hic = """ +[hic matrix] +file = small_test2.cool +title = cool with few interactions show_masked_bins = false (default) +depth = 200000 +file_type = hic_matrix +height = 5 + +[spacer] + +[hic matrix] +file = small_test2.cool +title = cool with few interactions show_masked_bins = true +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = true + +[x-axis] +""" +with open(os.path.join(ROOT, "browser_tracks_hic_small_test.ini"), 'w') as fh: + fh.write(browser_tracks_with_hic) +with open(os.path.join(ROOT, "browser_tracks_hic_small_test_invalid_colormap1.ini"), 'w') as fh: + fh.write(browser_tracks_with_hic.replace('[x-axis]', 'colormap = [\n[x-axis]')) +with open(os.path.join(ROOT, "browser_tracks_hic_small_test_invalid_colormap2.ini"), 'w') as fh: + fh.write(browser_tracks_with_hic.replace('[x-axis]', "colormap = ['a']\n[x-axis]")) +with open(os.path.join(ROOT, "browser_tracks_hic_small_test_invalid_colormap3.ini"), 'w') as fh: + fh.write(browser_tracks_with_hic.replace('[x-axis]', "colormap = fakeColormap\n[x-axis]")) + browser_tracks_with_hic = """ [hic matrix log] file = Li_et_al_2015.h5 @@ -187,6 +216,166 @@ with open(os.path.join(ROOT, "browser_tracks_hic_log-log.ini"), 'w') as fh: fh.write(browser_tracks_with_hic) +browser_tracks_with_mcool = """ +[x-axis] + +[mcool1] +file = matrix.mcool::/0 +depth = 1000000 +file_type = hic_matrix + +[mcool2] +file = matrix.mcool::/1 +depth = 1000000 +file_type = hic_matrix + +[mcool3] +file = matrix.mcool::/2 +depth = 1000000 +file_type = hic_matrix + +[mcool4] +file = matrix.mcool::/4 +depth = 1000000 +file_type = hic_matrix +""" + +with open(os.path.join(ROOT, "mcool.ini"), 'w') as fh: + fh.write(browser_tracks_with_mcool) + +browser_tracks_with_hic_small_2 = """ +[hic matrix] +file = small_test2.cool +title = cool with few interactions depth=10kb +file_type = hic_matrix +depth = 10000 + + +[x-axis] +""" + +with open(os.path.join(ROOT, "browser_tracks_hic_small_test_2.ini"), 'w') as fh: + fh.write(browser_tracks_with_hic_small_2) + +browser_tracks_with_one_interaction = """ +[hic matrix] +file = one_interaction_4chr.cool +title = cool with one interaction show_masked_bins = false +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = false + +[spacer] + +[hic matrix] +file = one_interaction_4chr.cool +title = cool with one interaction show_masked_bins = true +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = true + +[spacer] + +[hic matrix] +file = one_interaction_4chr.cool +title = cool with one interaction show_masked_bins = true transform = log +depth = 200000 +file_type = hic_matrix +height = 5 +show_masked_bins = true +transform = log + +[newtrack] +file_type = x_axis +""" + +with open(os.path.join(ROOT, "browser_tracks_hic_one_interaction_cool.ini"), 'w') as fh: + fh.write(browser_tracks_with_one_interaction) + +# I keep cool in the title but I use the h5 matrix +with open(os.path.join(ROOT, "browser_tracks_hic_one_interaction_h5.ini"), 'w') as fh: + fh.write(browser_tracks_with_one_interaction.replace('one_interaction_4chr.cool', 'one_interaction_4chr.h5')) +# I keep cool in the title but I use the h5 matrix +with open(os.path.join(ROOT, "browser_tracks_hic_one_interaction_diag_h5.ini"), 'w') as fh: + fh.write(browser_tracks_with_one_interaction.replace('one_interaction_4chr.cool', 'one_interaction_diag_4chr.h5')) +# >>> from HiCMatrix import hicmatrix +# >>> hic_ma = HiCMatrix.hiCMatrix(os.path.join(ROOT, 'small_test2.cool')) +# >>> instances, features = hic_ma.matrix.nonzero() +# >>> instances +# array([ 0, 0, 1, 1, 2, 3, 3, 3, 9166], dtype=int32) +# >>> features +# array([ 0, 3, 2, 3, 1, 0, 1, 3, 9166], dtype=int32) +# >>> hic_ma.matrix.data +# array([1, 1, 1, 1, 1, 1, 1, 1, 1], dtype=int32) +# >>> import numpy as np +# >>> hic_ma.matrix.data = np.array([10, 5, 2, 1, 2, 5, 1, 100, -20]) +# >>> hic_ma.save('pygenometracks/tests/test_data/small_test3.cool') + +browser_tracks_with_hic_small_3 = """ +[hic matrix] +file = small_test3.cool +title = cool with few interactions transform = no +depth = 200000 +file_type = hic_matrix +min_value = 0 +max_value = 50 + +[hic matrix] +file = small_test3.cool +title = cool with few interactions transform = log +transform = log +depth = 200000 +file_type = hic_matrix +min_value = 0 +max_value = 5 + +[hic matrix] +file = small_test3.cool +title = cool with few interactions transform = -log +transform = -log +depth = 200000 +file_type = hic_matrix +min_value = 0 +max_value = -5 + +[hic matrix] +file = small_test3.cool +title = cool with few interactions transform = log1p +transform = log1p +depth = 200000 +file_type = hic_matrix +min_value = 0.1 +max_value = 50 + +[x-axis] +""" + +with open(os.path.join(ROOT, "browser_tracks_hic_small_test_3.ini"), 'w') as fh: + fh.write(browser_tracks_with_hic_small_3) + +browser_tracks_with_hic_small_3b = """ +[hic matrix] +file = small_test3.cool +title = cool with few interactions +depth = 200000 +file_type = hic_matrix +transform = log1p + +[x-axis] +""" + +with open(os.path.join(ROOT, "browser_tracks_hic_small_test_3_invalid.ini"), 'w') as fh: + fh.write(browser_tracks_with_hic_small_3b) + +with open(os.path.join(ROOT, "browser_tracks_hic_small_test_3_invalid2.ini"), 'w') as fh: + fh.write(browser_tracks_with_hic_small_3b.replace('log1p', 'log')) + +with open(os.path.join(ROOT, "browser_tracks_hic_small_test_3_invalid3.ini"), 'w') as fh: + fh.write(browser_tracks_with_hic_small_3b.replace('log1p', '-log')) + + tolerance = 13 # default matplotlib pixed difference tolerance @@ -194,15 +383,15 @@ def test_plot_tracks_with_hic(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:2500000-3500000 "\ - "--trackLabelFraction 0.23 --width 38 " \ - "--dpi 130 --outFileName {1}" \ - "".format(os.path.join(ROOT, 'browser_tracks_hic.ini'), - outfile.name).split() + ini_file = os.path.join(ROOT, "browser_tracks_hic.ini") + region = "X:2500000-3500000" + expected_file = os.path.join(ROOT, 'master_plot_hic.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_plot_hic.png'), + res = compare_images(expected_file, outfile.name, tolerance) - print("saving test to {}".format(outfile.name)) assert res is None, res os.remove(outfile.name) @@ -212,15 +401,16 @@ def test_plot_tracks_with_hic_dec(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:2500000-3500000 "\ - "--trackLabelFraction 0.23 --width 38 " \ - "--dpi 130 --outFileName {1} --decreasingXAxis" \ - "".format(os.path.join(ROOT, 'browser_tracks_hic.ini'), - outfile.name).split() + ini_file = os.path.join(ROOT, "browser_tracks_hic.ini") + region = "X:2500000-3500000" + expected_file = os.path.join(ROOT, 'master_plot_hic_dec.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 --dpi 130 "\ + "--decreasingXAxis "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_plot_hic_dec.png'), + res = compare_images(expected_file, outfile.name, tolerance) - print("saving test to {}".format(outfile.name)) assert res is None, res os.remove(outfile.name) @@ -230,13 +420,14 @@ def test_plot_tracks_with_cool_region(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:2500000-3500000 "\ - "--trackLabelFraction 0.23 --width 38 " \ - "--dpi 130 --outFileName {1}" \ - "".format(os.path.join(ROOT, 'browser_tracks_cool.ini'), - outfile.name).split() + ini_file = os.path.join(ROOT, "browser_tracks_cool.ini") + region = "X:2500000-3500000" + expected_file = os.path.join(ROOT, 'master_plot_hic.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_plot_hic.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -247,34 +438,361 @@ def test_plot_hic_logmlog(): outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:2500000-3500000 "\ - "--trackLabelFraction 0.23 --width 38 " \ - "--dpi 130 --outFileName {1}" \ - "".format(os.path.join(ROOT, 'browser_tracks_hic_log-log.ini'), - outfile.name).split() + ini_file = os.path.join(ROOT, "browser_tracks_hic_log-log.ini") + region = "X:2500000-3500000" + expected_file = os.path.join(ROOT, 'master_plot_hic_log-log.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - res = compare_images(os.path.join(ROOT, 'master_plot_hic_log-log.png'), + res = compare_images(expected_file, outfile.name, tolerance) - print("saving test to {}".format(outfile.name)) assert res is None, res os.remove(outfile.name) -def test_plot_tracks_with_hic_rasterize_height(): +def test_plot_tracks_with_hic_rasterize_height_2chr(): + extension = '.pdf' - outfile = NamedTemporaryFile(suffix='.pdf', prefix='pyGenomeTracks_test_', + outfile = NamedTemporaryFile(suffix=extension, prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:2500000-2600000 "\ + ini_file = os.path.join(ROOT, "browser_tracks_hic_rasterize_height.ini") + bed_file = os.path.join(ROOT, 'regions_XY.bed') + args = f"--tracks {ini_file} --BED {bed_file} "\ + "--trackLabelFraction 0.23 --width 38 --dpi 10 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + for region in ['X:2500000-2600000', 'Y:0-1000000']: + region_str = region.replace(':', '-') + output_file = outfile.name[:-4] + '_' + region_str + extension + expected_file = os.path.join(ROOT, 'master_plot_hic_rasterize_height_' + + region_str + extension) + res = compare_images(expected_file, + output_file, tolerance) + assert res is None, res + + os.remove(output_file) + if extension == '.pdf': + os.remove(expected_file.replace(extension, '_pdf.png')) + + +def test_plot_tracks_with_hic_rasterize_height_2chr_individual(): + extension = '.pdf' + ini_file = os.path.join(ROOT, "browser_tracks_hic_rasterize_height.ini") + for region in ['X:2500000-2600000', 'Y:0-1000000']: + outfile = NamedTemporaryFile(suffix=extension, prefix='pyGenomeTracks_test_', + delete=False) + expected_file = os.path.join(ROOT, 'master_plot_hic_rasterize_height_' + + region.replace(':', '-') + extension) + + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 --dpi 10 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + if extension == '.pdf': + os.remove(expected_file.replace(extension, '_pdf.png')) + assert res is None, res + + +def test_plot_tracks_with_hic_small_test(): + extension = '.png' + + outfile = NamedTemporaryFile(suffix=extension, prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "browser_tracks_hic_small_test.ini") + bed_file = os.path.join(ROOT, 'regions_chr1XY.bed') + args = f"--tracks {ini_file} --BED {bed_file} "\ + "--trackLabelFraction 0.23 --width 38 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + for region in ['chr1:0-500000', 'chrX:2500000-2600000', 'chrY:0-1000000']: + region_str = region.replace(':', '-') + output_file = outfile.name[:-4] + '_' + region_str + extension + expected_file = os.path.join(ROOT, 'master_plot_hic_small_test_' + + region_str + extension) + res = compare_images(expected_file, + output_file, tolerance) + assert res is None, res + + os.remove(output_file) + + +# The tests with individual chromosome does not give the same result: +# For the empty the problem is the colorbar which is different +# when you do not load all data and the transformation of nan to 0 +# when the matrix is not empty + +def test_plot_tracks_with_hic_small_test_individual(): + extension = '.png' + ini_file = os.path.join(ROOT, "browser_tracks_hic_small_test.ini") + for region in ['chr1:0-500000']: # , 'chrX:2500000-2600000', 'chrY:-0-1000000']: + + outfile = NamedTemporaryFile(suffix=extension, prefix='pyGenomeTracks_test_', + delete=False) + expected_file = os.path.join(ROOT, 'master_plot_hic_small_test_' + + region.replace(':', '-') + extension) + + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_tracks_with_hic_small_other_chr_name(): + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + region = '1:0-200000' + expected_file = os.path.join(ROOT, 'master_plot_hic_small_test.png') + + for suf in [''] + ['_invalid_colormap' + s for s in ['1', '2', '3']]: + ini_file = os.path.join(ROOT, f'browser_tracks_hic_small_test{suf}.ini') + + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + if 'invalid' in ini_file: + os.remove(ini_file) + + +def test_plot_tracks_with_hic_small_above_chr_length(): + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, 'browser_tracks_hic_small_test.ini') + region = 'chrM:0-20000' + expected_file = os.path.join(ROOT, 'master_plot_hic_small_test_chrM.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_tracks_with_hic_small_above_chr_length_other_chrName(): + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, 'browser_tracks_hic_small_test.ini') + region = 'Y:90000000-100000000' + expected_file = os.path.join(ROOT, 'master_hic_small_test_above_chrY.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_hic_depth_smaller_binsize(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, 'browser_tracks_hic_small_test_2.ini') + region = 'chr1:0-100000' + expected_file = os.path.join(ROOT, 'master_hic_small_test_2.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_hic_plotting_region_smaller_binsize(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, 'browser_tracks_hic_small_test.ini') + region = 'chr1:0-5000' + expected_file = os.path.join(ROOT, 'master_hic_small_test_small_region.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_tracks_with_mcool(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + args = "--tracks {0} --region X:2500000-3500000 "\ "--trackLabelFraction 0.23 --width 38 " \ - "--dpi 10 --outFileName {1}" \ + "--dpi 130 --outFileName {1}" \ "".format(os.path.join(ROOT, - 'browser_tracks_hic_rasterize_height.ini'), + 'mcool.ini'), outfile.name).split() pygenometracks.plotTracks.main(args) res = compare_images(os.path.join(ROOT, - 'master_plot_hic_rasterize_height.pdf'), + 'master_mcool.png'), + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_tracks_with_hic_one_interaction_cool(): + extension = '.png' + + outfile = NamedTemporaryFile(suffix=extension, prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "browser_tracks_hic_one_interaction_cool.ini") + bed_file = os.path.join(ROOT, 'regions_chr1XY.bed') + args = f"--tracks {ini_file} --BED {bed_file} "\ + "--trackLabelFraction 0.23 --width 38 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + for region in ['chr1:0-500000', 'chrX:2500000-2600000', 'chrY:0-1000000']: + region_str = region.replace(':', '-') + output_file = outfile.name[:-4] + '_' + region_str + extension + expected_file = os.path.join(ROOT, 'master_plot_hic_one_interaction_withBED_' + + region_str + extension) + res = compare_images(expected_file, + output_file, tolerance) + assert res is None, res + + os.remove(output_file) + + +def test_plot_tracks_with_hic_one_interaction_h5(): + extension = '.png' + + outfile = NamedTemporaryFile(suffix=extension, prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "browser_tracks_hic_one_interaction_h5.ini") + bed_file = os.path.join(ROOT, 'regions_chr1XY.bed') + args = f"--tracks {ini_file} --BED {bed_file} "\ + "--trackLabelFraction 0.23 --width 38 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + for region in ['chr1:0-500000', 'chrX:2500000-2600000', 'chrY:0-1000000']: + region_str = region.replace(':', '-') + output_file = outfile.name[:-4] + '_' + region_str + extension + expected_file = os.path.join(ROOT, 'master_plot_hic_one_interaction_withBED_' + + region_str + extension) + res = compare_images(expected_file, + output_file, tolerance) + assert res is None, res + + os.remove(output_file) + + +def test_plot_tracks_with_hic_one_interaction_h5_individual(): + extension = '.png' + ini_file = os.path.join(ROOT, "browser_tracks_hic_one_interaction_h5.ini") + for region in ['chr1:0-500000', 'chrX:2500000-2600000', 'chrY:0-1000000']: + + outfile = NamedTemporaryFile(suffix=extension, prefix='pyGenomeTracks_test_', + delete=False) + expected_file = os.path.join(ROOT, 'master_plot_hic_one_interaction_withBED_' + + region.replace(':', '-') + extension) + + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +# The tests with individual chromosome with cool does not give the same result: +# For the empty the problem is the colorbar which is different +# when you do not load all data and the transformation of nan to 0 +# when the matrix is not empty +# In addition here because there was no data on diagonal it has been modified. +# When you load only one empty chromosome it is not empty anymore +def test_plot_tracks_with_hic_one_interaction_individual(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, 'browser_tracks_hic_one_interaction_cool.ini') + region = 'chr1:0-500000' + expected_file = os.path.join(ROOT, f"master_plot_hic_one_interaction_withBED_{region.replace(':', '-')}.png") + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, 'browser_tracks_hic_one_interaction_cool.ini') + region = 'chrY:0-1000000' + expected_file = os.path.join(ROOT, 'master_plot_hic_one_interaction_withRegion_chrY-0-1000000.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res os.remove(outfile.name) + + +def test_plot_tracks_with_hic_small3(): + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, 'browser_tracks_hic_small_test_3.ini') + region = 'chr1:0-200000' + expected_file = os.path.join(ROOT, 'master_hic_small_test_3.png') + + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.23 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_tracks_with_hic_small3_invalid(): + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + region = "chrM:0-20000" + for suf in ['', '2', '3']: + ini_file = os.path.join(ROOT, f"browser_tracks_hic_small_test_3_invalid{suf}.ini") + args = f"--tracks {ini_file} --region {region} "\ + f"--outFileName {outfile.name}".split() + try: + pygenometracks.plotTracks.main(args) + except Exception as e: + assert 'transformation can not be applied to' in str(e) + else: + raise Exception("The plot_tracks_with_hic_small3_invalid should fail.") + os.remove(ini_file) diff --git a/pygenometracks/tests/test_logScale.py b/pygenometracks/tests/test_logScale.py index 0c09afba..7b89ad4c 100644 --- a/pygenometracks/tests/test_logScale.py +++ b/pygenometracks/tests/test_logScale.py @@ -44,6 +44,68 @@ with open(os.path.join(ROOT, "log1p.ini"), 'w') as fh: fh.write(tracks) +tracks = """ +[test bigwig] +file = bigwig_chrx_2e6_5e6.bw +color = red +height = 5 +transform = no +title = bigwig transform = no +[test bigwig] +file = bigwig_chrx_2e6_5e6.bw +color = red +height = 5 +transform = no +orientation = inverted +grid = true +title = bigwig transform = no orientation = inverted grid = true + + +[spacer] + +[test bigwig log] +file = bigwig_chrx_2e6_5e6.bw +color = red +height = 5 +transform = log1p +title = bigwig transform = log1p +[test bigwig log] +file = bigwig_chrx_2e6_5e6.bw +color = red +height = 5 +transform = log1p +orientation = inverted +grid = true +title = bigwig transform = log1p orientation = inverted grid = true + +[spacer] + +[test bigwig log] +file = bigwig_chrx_2e6_5e6.bw +color = red +min_value = 0 +height = 5 +transform = log1p +title = bigwig transform = log1p min_value = 0 y_axis_values = original +y_axis_values = original + +[test bigwig log] +file = bigwig_chrx_2e6_5e6.bw +color = red +min_value = 0 +height = 5 +transform = log1p +orientation = inverted +grid = true +title = bigwig transform = log1p min_value = 0 y_axis_values = original orientation = inverted grid = true +y_axis_values = original + +[x-axis] +""" + +with open(os.path.join(ROOT, "log1p_grid.ini"), 'w') as fh: + fh.write(tracks) + tracks = """ [test bigwig] file = bigwig_chrx_2e6_5e6.bw @@ -55,6 +117,8 @@ with open(os.path.join(ROOT, "log_neg.ini"), 'w') as fh: fh.write(tracks) +with open(os.path.join(ROOT, "mlog_neg.ini"), 'w') as fh: + fh.write(tracks.replace('log', '-log')) tracks = """ @@ -130,19 +194,159 @@ with open(os.path.join(ROOT, "log.ini"), 'w') as fh: fh.write(tracks) +tracks = """ +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = blue +height = 5 +grid = true +title = bedgraph color = blue transform = no grid=true +transform = no + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = blue +height = 5 +grid = true +title = bedgraph color = blue transform = log grid=true +transform = log + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = red +height = 5 +grid = true +title = bedgraph color = red transform = log min_value = 1 grid=true +min_value = 1 +transform = log + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = green +height = 5 +grid = true +title = bedgraph color = green transform = log log_pseudocount = 2 min_value = 0 grid=true +transform = log +log_pseudocount = 2 +min_value = 0 + +[test bedgraph with operation] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = green +height = 5 +grid = true +title = bedgraph color = green operation = log(2+file) min_value = 0.7 grid=true +operation = log(2+file) +min_value = 0.7 + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = black +height = 5 +grid = true +title = bedgraph color = black transform = log2 log_pseudocount = 1 min_value = 0 grid=true +transform = log2 +log_pseudocount = 1 +min_value = 0 + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = black +height = 5 +grid = true +title = bedgraph color = black operation = log2(1+file) min_value = 0 grid=true +operation = log2(1+file) +min_value = 0 + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = black +height = 5 +grid = true +title = bedgraph color = black transform = log2 log_pseudocount = 1 min_value = 0 y_axis_values = original grid=true +transform = log2 +log_pseudocount = 1 +min_value = 0 +y_axis_values = original + +[x-axis] +""" + +with open(os.path.join(ROOT, "log_grid.ini"), 'w') as fh: + fh.write(tracks) + +tracks = """ +[x-axis] + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = blue +height = 5 +title = bedgraph color = blue transform = log +transform = log + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = blue +height = 5 +title = bedgraph color = blue transform = log y_axis_values = original +transform = log +y_axis_values = original + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = blue +height = 5 +title = bedgraph color = blue transform = log10 y_axis_values = original +transform = log10 +y_axis_values = original + +[test bedgraph] +file = GSM3182416_E12DHL_WT_Hoxd11vp.bedgraph.gz +color = blue +height = 5 +title = bedgraph color = blue transform = -log y_axis_values = original +transform = -log +y_axis_values = original +""" + +with open(os.path.join(ROOT, "log_more.ini"), 'w') as fh: + fh.write(tracks) + +with open(os.path.join(ROOT, "log_more_incorrect.ini"), 'w') as fh: + fh.write(tracks + 'type = invalid:a\n') + tolerance = 13 # default matplotlib pixed difference tolerance def test_log1p_track(): + outfile = NamedTemporaryFile(suffix='.png', prefix='log1p_test_', + delete=False) + ini_file = os.path.join(ROOT, "log1p.ini") + region = "X:2700000-3100000" + expected_file = os.path.join(ROOT, 'master_log1p.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_log1p_grid(): + outfile = NamedTemporaryFile(suffix='.png', prefix='log1p_grid_test_', + delete=False) + ini_file = os.path.join(ROOT, "log1p_grid.ini") region = "X:2700000-3100000" - outfile = NamedTemporaryFile(suffix='.png', prefix='log1p_test_', delete=False) - args = "--tracks {ini} --region {region} --trackLabelFraction 0.2 " \ - "--dpi 130 --outFileName {outfile}" \ - "".format(ini=os.path.join(ROOT, "log1p.ini"), - outfile=outfile.name, region=region).split() + expected_file = os.path.join(ROOT, 'master_log1p_grid.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_log1p.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -151,15 +355,36 @@ def test_log1p_track(): def test_log_tracks(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_log_', delete=False) - args = "--tracks {0} --region chr2:73,800,000-75,744,000 "\ - "--trackLabelFraction 0.2 --width 38 --dpi 130 " \ - "--outFileName {1}" \ - "".format(os.path.join(ROOT, "log.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', + prefix='pyGenomeTracks_test_log_', + delete=False) + ini_file = os.path.join(ROOT, "log.ini") + region = "chr2:73,800,000-75,744,000" + expected_file = os.path.join(ROOT, 'master_log.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_log_grid(): + + outfile = NamedTemporaryFile(suffix='.png', + prefix='pyGenomeTracks_test_loggrid_', + delete=False) + ini_file = os.path.join(ROOT, "log_grid.ini") + region = "chr2:73,800,000-75,744,000" + expected_file = os.path.join(ROOT, 'master_log_grid.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_log.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -168,13 +393,38 @@ def test_log_tracks(): class TestLogNegMethods(unittest.TestCase): def test_log_tracks_with_0values(self): - region = "X:2700000-3100000" - outfile = NamedTemporaryFile(suffix='.png', prefix='log_test_', delete=False) - args = "--tracks {ini} --region {region} --trackLabelFraction 0.2 " \ - "--dpi 130 --outFileName {outfile}" \ - "".format(ini=os.path.join(ROOT, "log_neg.ini"), - outfile=outfile.name, region=region).split() - with self.assertRaises(Exception) as context: - pygenometracks.plotTracks.main(args) - - assert("coverage contains values smaller or equal to" in str(context.exception)) + outfile = NamedTemporaryFile(suffix='.png', prefix='log_test_', + delete=False) + for pref in ['', 'm']: + ini_file = os.path.join(ROOT, f"{pref}log_neg.ini") + region = "X:2700000-3100000" + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + with self.assertRaises(Exception) as context: + pygenometracks.plotTracks.main(args) + + assert("coverage contains values smaller or equal to" in str(context.exception)) + os.remove(ini_file) + + +def test_log_more(): + + outfile = NamedTemporaryFile(suffix='.png', + prefix='pyGenomeTracks_test_log_', + delete=False) + for suf in ['', '_incorrect']: + ini_file = os.path.join(ROOT, f"log_more{suf}.ini") + region = "chr2:73,800,000-75,744,000" + expected_file = os.path.join(ROOT, 'master_log_more.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + # I remove the incorrect ini file + os.remove(ini_file) diff --git a/pygenometracks/tests/test_make_tracks.py b/pygenometracks/tests/test_make_tracks.py index 22f283a8..efdf4b91 100644 --- a/pygenometracks/tests/test_make_tracks.py +++ b/pygenometracks/tests/test_make_tracks.py @@ -11,14 +11,14 @@ def test_make_tracks(): - outfile = NamedTemporaryFile(suffix='.ini', prefix='pyGenomeTracks_test_', delete=False) - args = "--trackFiles {0} {1} {2} {3} --out {4}" \ - "".format(os.path.join(relative_path, 'Li_et_al_2015.h5'), - os.path.join(relative_path, 'bigwig_chrx_2e6_5e6.bw'), - os.path.join(relative_path, 'tad_classification.bed'), - os.path.join(relative_path, 'epilog.qcat.bgz'), - outfile.name).split() - print("using args: {}".format(" ".join(args))) + outfile = NamedTemporaryFile(suffix='.ini', prefix='pyGenomeTracks_test_', + delete=False) + all_paths = [os.path.join(relative_path, 'Li_et_al_2015.h5'), + os.path.join(relative_path, 'bigwig_chrx_2e6_5e6.bw'), + os.path.join(relative_path, 'tad_classification.bed'), + os.path.join(relative_path, 'epilog.qcat.bgz')] + args = f"--trackFiles {all_paths[0]} {all_paths[1]} {all_paths[2]}"\ + f" {all_paths[3]} --out {outfile.name}".split() pygenometracks.makeTracksFile.main(args) if filecmp.cmp(outfile.name, diff --git a/pygenometracks/tests/test_narrowPeakTrack.py b/pygenometracks/tests/test_narrowPeakTrack.py index 7f163a25..325ad8b0 100644 --- a/pygenometracks/tests/test_narrowPeakTrack.py +++ b/pygenometracks/tests/test_narrowPeakTrack.py @@ -70,15 +70,16 @@ def test_narrow_track(): + outfile = NamedTemporaryFile(suffix='.png', prefix='narrowTrack_test_', + delete=False) + ini_file = os.path.join(ROOT, "narrow_peak.ini") region = "X:2760000-2802000" - outfile = NamedTemporaryFile(suffix='.png', prefix='narrowTrack_test_', delete=False) - args = "--tracks {ini} --region {region} --trackLabelFraction 0.2 " \ - "--dpi 130 --outFileName {outfile}" \ - "".format(ini=os.path.join(ROOT, 'narrow_peak.ini'), - outfile=outfile.name, region=region).split() + expected_file = os.path.join(ROOT, 'master_narrowPeak.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_narrowPeak.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -86,15 +87,16 @@ def test_narrow_track(): def test_narrow_track_2(): + outfile = NamedTemporaryFile(suffix='.png', prefix='narrowTrack2_test_', + delete=False) + ini_file = os.path.join(ROOT, "narrow_peak2.ini") region = "X:2760000-2802000" - outfile = NamedTemporaryFile(suffix='.png', prefix='narrowTrack2_test_', delete=False) - args = "--tracks {ini} --region {region} --trackLabelFraction 0.2 " \ - "--dpi 130 --outFileName {outfile}" \ - "".format(ini=os.path.join(ROOT, 'narrow_peak2.ini'), - outfile=outfile.name, region=region).split() + expected_file = os.path.join(ROOT, 'master_narrowPeak2.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_narrowPeak2.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res diff --git a/pygenometracks/tests/test_non_classical_bed.py b/pygenometracks/tests/test_non_classical_bed.py new file mode 100644 index 00000000..528d4c45 --- /dev/null +++ b/pygenometracks/tests/test_non_classical_bed.py @@ -0,0 +1,352 @@ +# -*- coding: utf-8 -*- +import matplotlib as mpl +mpl.use('agg') +from matplotlib.testing.compare import compare_images +from tempfile import NamedTemporaryFile +import os.path +import pygenometracks.plotTracks + + +ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), + "test_data") + +browser_tracks = """ +[macs2 broadPeak] +file = broadPeak.broadPeak +title = broadPeak +file_type = bed + +[spacer] + +[macs2 gappedPeak] +file = gappedPeak.gappedPeak +title = gappedPeak +file_type = bed + +[spacer] + +[macs2 filteredbed] +file = filtered.results.bed +title = filtered.results.bed (strange format) +file_type = bed +""" +with open(os.path.join(ROOT, "bed_unusual_formats.ini"), 'w') as fh: + fh.write(browser_tracks) + +browser_tracks = """ +[strange_strand] +file = strange_strand.bed +""" +with open(os.path.join(ROOT, "strange_strand.ini"), 'w') as fh: + fh.write(browser_tracks) + + +browser_tracks = """ +[invalid_strand] +file = invalid_strand.bed +""" +with open(os.path.join(ROOT, "invalid_strand.ini"), 'w') as fh: + fh.write(browser_tracks) + +browser_tracks = """ +[invalid_rgb] +file = invalid_rgb.bed +title = first line valid but neg invalid +color = bed_rgb + +[invalid_rgb2] +file = invalid_rgb2.bed +title = first line invalid +color = bed_rgb +""" +with open(os.path.join(ROOT, "invalid_rgb.ini"), 'w') as fh: + fh.write(browser_tracks) + +browser_tracks = """ +[invalid_blockCount] +file = invalid_blockCount.bed +title = invalid block count in first line +color = bed_rgb + +[spacer] + +[invalid_blockCount] +file = invalid_blockCount2.bed +title = invalid block count in not first line -> bedtools raised an error +style = UCSC +height = 2 +""" +with open(os.path.join(ROOT, "invalid_blockCount.ini"), 'w') as fh: + fh.write(browser_tracks) + +browser_tracks = """ +[invalid_CDScoo] +file = invalid_CDScoo.bed +title = invalid CDS coordinate in first line rgb is ignored +color = bed_rgb + +[spacer] + +[invalid_CDScoo2] +file = invalid_CDScoo2.bed +title = invalid CDS coordinate in not first line rgb can be used +color = bed_rgb +height = 2 + +[spacer] + +[invalid_CDScoo3] +file = invalid_CDScoo3.bed +title = invalid CDS coordinate in not first line bed12 can be used +color = bed_rgb +style = UCSC +height = 2 +""" +with open(os.path.join(ROOT, "invalid_CDScoo.ini"), 'w') as fh: + fh.write(browser_tracks) + +browser_tracks = """ +[invalid_blocks] +file = invalid_blocks.bed +title = block_length is not integer in first line, block info is ignored +style = UCSC + +[spacer] + +[invalid_blocks2] +file = invalid_blocks2.bed +title = block_length is not integer in not first line blocks are used +style = UCSC +height = 4 +""" +with open(os.path.join(ROOT, "invalid_blocks.ini"), 'w') as fh: + fh.write(browser_tracks) + +browser_tracks = """ +[invalid_blocks3] +file = invalid_blocks3.bed +title = block_count_inconsistent between block count and others +""" +with open(os.path.join(ROOT, "invalid_blocks3.ini"), 'w') as fh: + fh.write(browser_tracks) + +browser_tracks = """ +[invalid_blocks4] +file = invalid_blocks4.bed +title = block_count_inconsistent between lengths and others +""" +with open(os.path.join(ROOT, "invalid_blocks4.ini"), 'w') as fh: + fh.write(browser_tracks) + +browser_tracks = """ +[bed with 0 block] +file = example_zeroBlock.bed +title = example with number of block = 0 will fail +""" +with open(os.path.join(ROOT, "invalid_zero_block.ini"), 'w') as fh: + fh.write(browser_tracks) + +browser_tracks = """ +[invalid_score] +file = invalid_score.bed +title = invalid score in first line strand and rgb is ignored +color = bed_rgb + +[spacer] + +[invalid_score2] +file = invalid_score2.bed +title = invalid score in not first line strand and rgb can be used +color = bed_rgb +height = 2 +""" +with open(os.path.join(ROOT, "invalid_score.ini"), 'w') as fh: + fh.write(browser_tracks) + +tolerance = 13 # default matplotlib pixed difference tolerance + + +def test_plot_tracks_bed_unusual_format(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "bed_unusual_formats.ini") + region = "X:20000-40000" + expected_file = os.path.join(ROOT, 'master_bed_unusual_formats.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_tracks_bed_strange_strand(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "strange_strand.ini") + region = "chr1:0-500" + expected_file = os.path.join(ROOT, 'master_strange_strand.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_tracks_bed_invalid_strand(): + + tolerance = 5 + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "invalid_strand.ini") + region = "chr1:0-500" + expected_file = os.path.join(ROOT, 'master_strange_strand.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + os.remove(ini_file) + + +def test_plot_tracks_bed_invalid_rgb(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "invalid_rgb.ini") + region = "chr1:0-500" + expected_file = os.path.join(ROOT, 'master_invalid_rgb.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_tracks_bed_invalid_blockCount(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "invalid_blockCount.ini") + region = "chrX:15000-24000" + expected_file = os.path.join(ROOT, 'master_invalid_blockCount.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_tracks_bed_invalid_CDScoo(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "invalid_CDScoo.ini") + region = "chrX:15000-24000" + expected_file = os.path.join(ROOT, 'master_invalid_CDScoo.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_tracks_bed_invalid_blocks(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "invalid_blocks.ini") + region = "chrX:15000-24000" + expected_file = os.path.join(ROOT, 'master_invalid_blocks.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_tracks_bed_invalid_score(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "invalid_score.ini") + region = "chrX:15000-24000" + expected_file = os.path.join(ROOT, 'master_invalid_score.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_plot_tracks_bed_invalid_block_count(): + + region = "chrX:15000-24000" + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + for suf in ['3', '4']: + ini_file = os.path.join(ROOT, f"invalid_blocks{suf}.ini") + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + try: + pygenometracks.plotTracks.main(args) + except Exception as e: + assert 'The number of blocks:' in str(e) + else: + raise Exception(f"bed_invalid_block{suf} should fail.") + os.remove(ini_file) + + +def test_plot_tracks_bed_invalid_zero_block(): + + region = "chr1:0-500" + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "invalid_zero_block.ini") + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + try: + pygenometracks.plotTracks.main(args) + except Exception as e: + assert 'File type detected is bed12 but line' in str(e) + else: + raise Exception("invalid_zero_block should fail.") + os.remove(ini_file) diff --git a/pygenometracks/tests/test_plot_tracks.py b/pygenometracks/tests/test_plot_tracks.py index f23f63b0..8a91f6b5 100644 --- a/pygenometracks/tests/test_plot_tracks.py +++ b/pygenometracks/tests/test_plot_tracks.py @@ -224,20 +224,29 @@ with open(os.path.join(ROOT, "empty.ini"), 'w') as fh: fh.write(browser_tracks) +browser_tracks = """ +[bed] +file = empty.bed +overlay_previous = yes +""" +with open(os.path.join(ROOT, "firstTrackOverlay.ini"), 'w') as fh: + fh.write(browser_tracks) tolerance = 13 # default matplotlib pixed difference tolerance def test_plot_tracks(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3500000 --trackLabelFraction 0.2" \ - " --width 38 --dpi 130 --outFileName {1}" \ - "".format(os.path.join(ROOT, "browser_tracks.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "browser_tracks.ini") + region = "X:3000000-3500000" + expected_file = os.path.join(ROOT, 'master_plot.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_plot.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -246,14 +255,34 @@ def test_plot_tracks(): def test_plot_tracks_empty_files(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3500000 --trackLabelFraction 0.2" \ - " --width 38 --dpi 130 --outFileName {1}" \ - "".format(os.path.join(ROOT, "empty.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "empty.ini") + region = "X:3000000-3500000" + expected_file = os.path.join(ROOT, 'master_empty.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_first_track_overlay(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "firstTrackOverlay.ini") + region = "X:3000000-3500000" + expected_file = os.path.join(ROOT, 'master_empty2.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_empty.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -262,14 +291,16 @@ def test_plot_tracks_empty_files(): def test_plot_tracks_existing_chr_empty_tracks(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:0-1000000 --trackLabelFraction 0.2" \ - " --width 38 --dpi 130 --outFileName {1}" \ - "".format(os.path.join(ROOT, "browser_tracks.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "browser_tracks.ini") + region = "X:0-1000000" + expected_file = os.path.join(ROOT, 'master_plot_2.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_plot_2.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -278,14 +309,16 @@ def test_plot_tracks_existing_chr_empty_tracks(): def test_plot_tracks_missing_chr(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region Y:0-1000000 --trackLabelFraction 0.2" \ - " --width 38 --dpi 130 --outFileName {1}" \ - "".format(os.path.join(ROOT, "browser_tracks.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "browser_tracks.ini") + region = "Y:0-1000000" + expected_file = os.path.join(ROOT, 'master_plot_3.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_plot_3.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -294,14 +327,17 @@ def test_plot_tracks_missing_chr(): def test_plot_tracks_dec(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3500000 --trackLabelFraction 0.2" \ - " --width 38 --dpi 130 --outFileName {1} --decreasingXAxis" \ - "".format(os.path.join(ROOT, "browser_tracks.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "browser_tracks.ini") + region = "X:3000000-3500000" + expected_file = os.path.join(ROOT, 'master_plot_dec.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + "--decreasingXAxis "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_plot_dec.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res diff --git a/pygenometracks/tests/test_scaleBar.py b/pygenometracks/tests/test_scaleBar.py index 40cb4c5d..928c7548 100644 --- a/pygenometracks/tests/test_scaleBar.py +++ b/pygenometracks/tests/test_scaleBar.py @@ -76,14 +76,16 @@ def test_scale_bar(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3300000 --trackLabelFraction 0.2" \ - " --width 38 --dpi 130 --outFileName {1}" \ - "".format(os.path.join(ROOT, "scale_bar.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "scale_bar.ini") + region = "X:3000000-3300000" + expected_file = os.path.join(ROOT, 'master_scale_bar.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_scale_bar.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -92,14 +94,16 @@ def test_scale_bar(): def test_scale_bar_zoom(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3200000-3300000 --trackLabelFraction 0.2" \ - " --width 38 --dpi 130 --outFileName {1}" \ - "".format(os.path.join(ROOT, "scale_bar.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "scale_bar.ini") + region = "X:3200000-3300000" + expected_file = os.path.join(ROOT, 'master_scale_bar_zoom.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_scale_bar_zoom.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res diff --git a/pygenometracks/tests/test_tracks_label.py b/pygenometracks/tests/test_tracks_label.py index e50e5715..89fede04 100644 --- a/pygenometracks/tests/test_tracks_label.py +++ b/pygenometracks/tests/test_tracks_label.py @@ -22,14 +22,16 @@ def test_regular_width_label(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3500000 --trackLabelFraction 0.2" \ - " --width 38 --dpi 130 --outFileName {1}" \ - "".format(os.path.join(ROOT, "title.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "title.ini") + region = "X:3000000-3500000" + expected_file = os.path.join(ROOT, 'master_title_0.2.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.2 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_title_0.2.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -38,14 +40,16 @@ def test_regular_width_label(): def test_large_width_label(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3500000 --trackLabelFraction 0.5" \ - " --width 38 --dpi 130 --outFileName {1}" \ - "".format(os.path.join(ROOT, "title.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "title.ini") + region = "X:3000000-3500000" + expected_file = os.path.join(ROOT, 'master_title_0.5.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.5 --width 38 --dpi 130 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_title_0.5.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -54,15 +58,17 @@ def test_large_width_label(): def test_large_width_label_ral(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3500000 --trackLabelFraction 0.5" \ - " --width 38 --dpi 130 --outFileName {1}" \ - " --trackLabelHAlign right" \ - "".format(os.path.join(ROOT, "title.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "title.ini") + region = "X:3000000-3500000" + expected_file = os.path.join(ROOT, 'master_title_0.5_ral.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.5 --width 38 --dpi 130 "\ + "--trackLabelHAlign right "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_title_0.5_ral.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -71,15 +77,17 @@ def test_large_width_label_ral(): def test_large_width_label_cal(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3500000 --trackLabelFraction 0.5" \ - " --width 38 --dpi 130 --outFileName {1}" \ - " --trackLabelHAlign center" \ - "".format(os.path.join(ROOT, "title.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "title.ini") + region = "X:3000000-3500000" + expected_file = os.path.join(ROOT, 'master_title_0.5_cal.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.5 --width 38 --dpi 130 "\ + "--trackLabelHAlign center "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_title_0.5_cal.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -88,15 +96,17 @@ def test_large_width_label_cal(): def test_large_width_label_cal_dpi250(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3500000 --trackLabelFraction 0.5" \ - " --width 38 --dpi 250 --outFileName {1}" \ - " --trackLabelHAlign center" \ - "".format(os.path.join(ROOT, "title.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "title.ini") + region = "X:3000000-3500000" + expected_file = os.path.join(ROOT, 'master_title_0.5_cal_d250.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.5 --width 38 --dpi 250 "\ + "--trackLabelHAlign center "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_title_0.5_cal_d250.png'), + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res @@ -105,14 +115,35 @@ def test_large_width_label_cal_dpi250(): def test_large_width_label_big_font(): - outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', delete=False) - args = "--tracks {0} --region X:3000000-3500000 --trackLabelFraction 0.5" \ - " --width 38 --dpi 130 --outFileName {1} --fontSize 20" \ - "".format(os.path.join(ROOT, "title.ini"), - outfile.name).split() + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "title.ini") + region = "X:3000000-3500000" + expected_file = os.path.join(ROOT, 'master_title_0.5_fs20.png') + args = f"--tracks {ini_file} --region {region} "\ + "--trackLabelFraction 0.5 --width 38 --dpi 130 "\ + "--fontSize 20 "\ + f"--outFileName {outfile.name}".split() pygenometracks.plotTracks.main(args) - print("saving test to {}".format(outfile.name)) - res = compare_images(os.path.join(ROOT, 'master_title_0.5_fs20.png'), + res = compare_images(expected_file, + outfile.name, tolerance) + assert res is None, res + + os.remove(outfile.name) + + +def test_fixed_height(): + + outfile = NamedTemporaryFile(suffix='.png', prefix='pyGenomeTracks_test_', + delete=False) + ini_file = os.path.join(ROOT, "title.ini") + region = "X:3000000-3500000" + expected_file = os.path.join(ROOT, 'master_title_force_height.png') + args = f"--tracks {ini_file} --region {region} "\ + "--height 10 --title force_height "\ + f"--outFileName {outfile.name}".split() + pygenometracks.plotTracks.main(args) + res = compare_images(expected_file, outfile.name, tolerance) assert res is None, res diff --git a/pygenometracks/tracks/BedGraphMatrixTrack.py b/pygenometracks/tracks/BedGraphMatrixTrack.py index fdcbeb0b..ba214593 100644 --- a/pygenometracks/tracks/BedGraphMatrixTrack.py +++ b/pygenometracks/tracks/BedGraphMatrixTrack.py @@ -10,7 +10,7 @@ class BedGraphMatrixTrack(BedGraphTrack): SUPPORTED_ENDINGS = ['.bm', '.bm.gz', '.bedgraphmatrix', '.bm.bgz'] TRACK_TYPE = 'bedgraph_matrix' - OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + """ + OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + f""" # a bedgraph matrix file is like a bedgraph, except that per bin there # are more than one value separated by tab: E.g. # This file type is produced by HiCExplorer tool hicFindTads and contains @@ -25,7 +25,8 @@ class BedGraphMatrixTrack(BedGraphTrack): # If the type is not lines, you can choose to keep the matrix as not rasterized # (only used if you use pdf or svg output format) by using: # rasterize = false -# The different options for color maps can be found here: https://matplotlib.org/users/colormaps.html +# The different options for color maps can be found here: +# https://matplotlib.org/users/colormaps.html # the default color map is viridis # If you want your own colormap you can put the values of the color you want # For example, colormap = ['blue', 'yellow', 'red'] @@ -40,8 +41,8 @@ class BedGraphMatrixTrack(BedGraphTrack): # only when type lines is used. Adds horizontal lines plot_horizontal_lines = false -file_type = {} - """.format(TRACK_TYPE) +file_type = {TRACK_TYPE} + """ DEFAULTS_PROPERTIES = {'max_value': None, 'min_value': None, # In next 1.0 change matrix to lines @@ -51,6 +52,7 @@ class BedGraphMatrixTrack(BedGraphTrack): 'plot_horizontal_lines': False, 'orientation': None, 'rasterize': True, + 'region': None, # Cannot be set manually but is set by tracksClass 'colormap': DEFAULT_BEDGRAPHMATRIX_COLORMAP} NECESSARY_PROPERTIES = ['file'] SYNONYMOUS_PROPERTIES = {'max_value': {'auto': None}, @@ -78,11 +80,11 @@ def __init__(self, properties_dict): def set_properties_defaults(self): # To remove in next 1.0 if 'type' not in self.properties: - self.log.warning("Deprecated Warning: The section {} did" + self.log.warning("Deprecated Warning: The section " + f"{self.properties['section_name']} did" " not specify the type. For the moment" " the default type is matrix but in the" - " next version it will be lines." - "".format(self.properties['section_name'])) + " next version it will be lines.\n") # End to remove GenomeTrack.set_properties_defaults(self) if self.properties['type'] == 'matrix': diff --git a/pygenometracks/tracks/BedGraphTrack.py b/pygenometracks/tracks/BedGraphTrack.py index 3870c915..e426cebd 100644 --- a/pygenometracks/tracks/BedGraphTrack.py +++ b/pygenometracks/tracks/BedGraphTrack.py @@ -1,5 +1,5 @@ from . GenomeTrack import GenomeTrack -from .. utilities import file_to_intervaltree, plot_coverage, InputError, transform +from .. utilities import file_to_intervaltree, plot_coverage, InputError, transform, change_chrom_names import numpy as np import pyBigWig import tempfile @@ -15,13 +15,15 @@ class BedGraphTrack(GenomeTrack): '.bedGraph', '.bedGraph.gz', '.bedGraph.bgz', '.bdg', '.bdg.gz', '.bdg.bgz'] TRACK_TYPE = 'bedgraph' - OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + """ + OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + f""" color = green +# To use a different color for negative values +#negative_color = red # To use transparency, you can use alpha # default is 1 # alpha = 0.5 # the default for min_value and max_value is 'auto' which means that the scale will go -# from the minimum value found in the region plotted to the maximum value found. +# roughly from the minimum value found in the region plotted to the maximum value found. min_value = 0 #max_value = auto # to convert missing data (NaNs) into zeros. Otherwise, missing data is not plotted. @@ -75,8 +77,10 @@ class BedGraphTrack(GenomeTrack): # gives the transformed values, if you prefer to see # the original values: #y_axis_values = original -file_type = {} - """.format(TRACK_TYPE) +# If you want to have a grid on the y-axis +#grid = true +file_type = {TRACK_TYPE} + """ DEFAULTS_PROPERTIES = {'max_value': None, 'min_value': None, 'show_data_range': True, @@ -90,11 +94,13 @@ class BedGraphTrack(GenomeTrack): 'rasterize': False, 'number_of_bins': 700, 'type': 'fill', + 'region': None, # Cannot be set manually but is set by tracksClass 'transform': 'no', 'log_pseudocount': 0, 'y_axis_values': 'transformed', 'second_file': None, - 'operation': 'file'} + 'operation': 'file', + 'grid': False} NECESSARY_PROPERTIES = ['file'] SYNONYMOUS_PROPERTIES = {'max_value': {'auto': None}, 'min_value': {'auto': None}} @@ -106,7 +112,7 @@ class BedGraphTrack(GenomeTrack): 'log10'], 'y_axis_values': ['original', 'transformed']} BOOLEAN_PROPERTIES = ['show_data_range', 'nans_to_zeros', - 'use_middle', 'rasterize'] + 'use_middle', 'rasterize', 'grid'] STRING_PROPERTIES = ['file', 'file_type', 'overlay_previous', 'orientation', 'summary_method', 'title', 'color', 'negative_color', @@ -123,16 +129,16 @@ class BedGraphTrack(GenomeTrack): def __init__(self, properties_dict): super(BedGraphTrack, self).__init__(properties_dict) + self.tbx2 = None self.load_file() - self.tbx2 = None self.interval_tree2 = None if 'second_file' in self.properties['operation']: if self.properties['second_file'] is None: - raise InputError("operation: {} requires to set the parameter" - " second_file." - "".format(self.properties['operation'])) + raise InputError(f"operation: {self.properties['operation']}" + " requires to set the parameter" + " second_file.") else: if self.properties['second_file'].endswith(".bgz"): # from the tabix file is not possible to know the @@ -160,7 +166,7 @@ def set_properties_defaults(self): self.log.warning("When an operation is computed" " between 2 files" " a summary_method needs to be" - " used. Will use mean.") + " used. Will use mean.\n") self.properties['summary_method'] = 'mean' if self.properties['operation'] != 'file': @@ -172,7 +178,7 @@ def set_properties_defaults(self): "'y_axis_values' was set to 'original'. " "'y_axis_values' can only be set to " "'original' when 'transform' is used.\n" - " It will be set as 'transformed'.") + " It will be set as 'transformed'.\n") self.properties['y_axis_values'] = 'transformed' def load_file(self): @@ -184,10 +190,13 @@ def load_file(self): try: self.tbx = pysam.TabixFile(self.properties['file']) except IOError: - self.interval_tree, __, __ = file_to_intervaltree(self.properties['file']) + self.interval_tree, __, __ = file_to_intervaltree(self.properties['file'], + self.properties['region']) # load the file as an interval tree else: - self.interval_tree, __, __ = file_to_intervaltree(self.properties['file']) + self.interval_tree, __, __ = file_to_intervaltree(self.properties['file'], + self.properties['region']) + self.num_fields = None def _get_row_data(self, row, tbx_var='self.tbx'): @@ -242,11 +251,11 @@ def get_scores(self, chrom_region, start_region, end_region, if tbx is not None: if chrom_region not in tbx.contigs: chrom_region_before = chrom_region - chrom_region = self.change_chrom_names(chrom_region) + chrom_region = change_chrom_names(chrom_region) if chrom_region not in tbx.contigs: self.log.warning("*Warning*\nNeither " + chrom_region_before + " nor " - + chrom_region + " existss as a " + + chrom_region + " exists as a " "chromosome name inside the bedgraph " "file. This will generate an empty " "track!!\n") @@ -260,13 +269,14 @@ def get_scores(self, chrom_region, start_region, end_region, inttree = eval(inttree_var) if chrom_region not in list(inttree): chrom_region_before = chrom_region - chrom_region = self.change_chrom_names(chrom_region) + chrom_region = change_chrom_names(chrom_region) if chrom_region not in list(inttree): - self.log.warning("*Warning*\nNeither " - + chrom_region_before + " nor " - + chrom_region + " existss as a " - "chromosome name inside the bedgraph " - "file. This will generate an empty " + self.log.warning("*Warning*\nNo interval was found when " + "overlapping with both " + f"{chrom_region_before}:{start_region}-{end_region}" + f" and {chrom_region}:{start_region}-{end_region}" + " inside the bedgraph file. " + "This will generate an empty " "track!!\n") return score_list, pos_list chrom_region = self.check_chrom_str_bytes(inttree, chrom_region) @@ -290,7 +300,15 @@ def plot(self, ax, chrom_region, start_region, end_region): score_list, pos_list = self.get_scores(chrom_region, start_region, end_region) if pos_list == []: return - score_list = [float(x[0]) for x in score_list] + try: + score_list = [float(x[0]) for x in score_list] + except ValueError as ve: + if "could not convert string to float: 'NA'" in str(ve): + self.log.warning("*Warning*\nNA were found in the bedgraph" + " will be replaced by nan.\n") + score_list = [float(x[0]) if x[0] != 'NA' else float('nan') for x in score_list] + else: + raise ve if self.properties['use_middle']: x_values = np.asarray([(t[0] + t[1]) / 2 for i, t in enumerate(pos_list) @@ -318,10 +336,9 @@ def plot(self, ax, chrom_region, start_region, end_region): new_score_list = eval('[' + operation + ' for file in score_list]') new_score_list = np.array(new_score_list) except Exception as e: - raise Exception("The operation in section {} could not be" - " computed: {}". - format(self.properties['section_name'], - e)) + raise Exception("The operation in section " + f"{self.properties['section_name']} could not " + f"be computed: {e}") else: score_list = new_score_list @@ -342,10 +359,9 @@ def plot(self, ax, chrom_region, start_region, end_region): new_score_list = eval('[' + operation + ' for file,second_file in zip(score_list, score_list2)]') new_score_list = np.array(new_score_list) except Exception as e: - raise Exception("The operation in section {} could not be" - " computed: {}". - format(self.properties['section_name'], - e)) + raise Exception("The operation in section " + f"{self.properties['section_name']} could not" + f" be computed: {e}") else: score_list = new_score_list @@ -358,7 +374,8 @@ def plot(self, ax, chrom_region, start_region, end_region): self.size, self.properties['color'], self.properties['negative_color'], - self.properties['alpha']) + self.properties['alpha'], + self.properties['grid']) ymax = self.properties['max_value'] ymin = self.properties['min_value'] @@ -368,13 +385,13 @@ def plot(self, ax, chrom_region, start_region, end_region): else: ymax = transform(np.array([ymax]), self.properties['transform'], self.properties['log_pseudocount'], - 'ymax') + 'ymax')[0] if ymin is None: ymin = plot_ymin else: ymin = transform(np.array([ymin]), self.properties['transform'], self.properties['log_pseudocount'], - 'ymin') + 'ymin')[0] if self.properties['orientation'] == 'inverted': ax.set_ylim(ymax, ymin) @@ -394,7 +411,7 @@ def get_values_as_bigwig(self, score_list, pos_list, chrom_region, # the last position of the pos_list bw.addHeader([(chrom_region, pos_list[-1][1])]) # The starts, ends, score are stored - bw.addEntries(np.repeat(chrom_region, len(pos_list)), + bw.addEntries([chrom_region] * len(pos_list), [p[0] for p in pos_list], ends=[p[1] for p in pos_list], values=score_list) @@ -436,7 +453,8 @@ def plot_y_axis(self, ax, plot_axis): super(BedGraphTrack, self).plot_y_axis(ax, plot_axis, self.properties['transform'], self.properties['log_pseudocount'], - self.properties['y_axis_values']) + self.properties['y_axis_values'], + self.properties['grid']) def __del__(self): if self.tbx is not None: diff --git a/pygenometracks/tracks/BedTrack.py b/pygenometracks/tracks/BedTrack.py index b17efbcd..f61d990f 100644 --- a/pygenometracks/tracks/BedTrack.py +++ b/pygenometracks/tracks/BedTrack.py @@ -3,7 +3,7 @@ # To remove next 1.0 from .. readGtf import ReadGtf # End to remove -from .. utilities import opener, get_length_w, count_lines +from .. utilities import opener, get_length_w, count_lines, temp_file_from_intersect, change_chrom_names import matplotlib from matplotlib import font_manager from matplotlib.patches import Rectangle, Polygon @@ -17,6 +17,7 @@ DISPLAY_BED_VALID = ['collapsed', 'triangles', 'interleaved', 'stacked'] DISPLAY_BED_SYNONYMOUS = {'interlaced': 'interleaved', 'domain': 'interleaved'} DEFAULT_DISPLAY_BED = 'stacked' +AROUND_REGION = 100000 class BedTrack(GenomeTrack): @@ -25,14 +26,14 @@ class BedTrack(GenomeTrack): 'bed.gz', 'bed3.gz', 'bed4.gz', 'bed5.gz', 'bed6.gz', 'bed9.gz', 'bed12.gz'] TRACK_TYPE = 'bed' - OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + """ + OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + f""" # If the bed file contains the exon # structure (bed 12) then this is plotted. Otherwise # a region **with direction** is plotted. # If the bed file contains a column for color (column 9), then this color can be used by # setting: -# color = bed_rgb -#if color is a valid colormap name (like RbBlGn), then the score is mapped +#color = bed_rgb +# if color is a valid colormap name (like RbBlGn), then the score (column 5) is mapped # to the colormap. # In this case, the the min_value and max_value for the score can be provided, otherwise # the maximum score and minimum score found are used. @@ -41,8 +42,6 @@ class BedTrack(GenomeTrack): #max_value=100 # If the color is simply a color name, then this color is used and the score is not considered. color = darkblue -# height of track in cm -height = 5 # whether printing the labels labels = false # optional: @@ -54,21 +53,24 @@ class BedTrack(GenomeTrack): # optional: line_width #line_width = 0.5 # the display parameter defines how the bed file is plotted. -# The options are ['collapsed', 'interleaved', 'triangles'] These options asume that the regions do not overlap. +# Default is 'stacked' where regions are plotted on different lines so +# we can see all regions and all labels. +# The other options are ['collapsed', 'interleaved', 'triangles'] +# These options assume that the regions do not overlap. # `collapsed`: The bed regions are plotted one after the other in one line. # `interleaved`: The bed regions are plotted in two lines, first up, then down, then up etc. -# if display is not given, then each region is plotted using the gene style # optional, default is black. To remove the border, simply set 'border_color' to none # Not used in tssarrow style #border_color = black -# style to plot the genes when they have exon information +# style to plot the genes when the display is not triangles #style = UCSC #style = flybase #style = tssarrow # maximum number of gene rows to be plotted. This # field is useful to limit large number of close genes # to be printed over many rows. When several images want -# to be combined this must be set to get equal size, otherwise, on each image the height of each gene changes +# to be combined this must be set to get equal size +# otherwise, on each image the height of each gene changes #gene_rows = 10 # by default the ymax is the number of # rows occupied by the genes in the region plotted. However, @@ -98,12 +100,9 @@ class BedTrack(GenomeTrack): # If you want that the tip of the arrow correspond to # the extremity of the interval use: # arrowhead_included = true -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale -#overlay_previous = yes # optional. If not given is guessed from the file ending. -file_type = {} - """.format(TRACK_TYPE) +file_type = {TRACK_TYPE} + """ DEFAULTS_PROPERTIES = {'fontsize': 12, 'orientation': None, @@ -126,6 +125,7 @@ class BedTrack(GenomeTrack): 'arrowhead_included': False, 'color_utr': 'grey', 'height_utr': 1, + 'region': None, # Cannot be set manually but is set by tracksClass 'arrow_length': None, 'all_labels_inside': False, 'labels_in_margin': False} @@ -164,7 +164,7 @@ def __init__(self, *args, **kwarg): # this is bed3, bed4, bed5, bed6, bed8, bed9 or bed12 self.len_w = None # this is the length of the letter 'w' given the font size self.interval_tree = {} # interval tree of the bed regions - self.interval_tree, min_score, max_score = self.process_bed() + self.interval_tree, min_score, max_score = self.process_bed(self.properties['region']) if self.colormap is not None: if self.properties['min_value'] is not None: min_score = self.properties['min_value'] @@ -205,53 +205,58 @@ def set_properties_defaults(self): if self.colormap == self.properties[param]: self.parametersUsingColormap.append(param) else: - self.log.warning("*WARNING* section {0}: {1} was set to {2}, " - "but {3} was set to {4}. " + self.log.warning("*WARNING* section " + f"{self.properties['section_name']}: " + f"{param} was set to " + f"{self.properties[param]}, but " + f"{self.parametersUsingColormap[0]}" + f" was set to {self.colormap}. " "It is not possible to have multiple" - " colormap. {1} set to {5}" - "".format(self.properties['section_name'], - param, self.properties[param], - self.parametersUsingColormap[0], - self.colormap, - self.DEFAULTS_PROPERTIES[param])) + f" colormap. {param} set to " + f"{self.DEFAULTS_PROPERTIES[param]}.\n") self.properties[param] = self.DEFAULTS_PROPERTIES[param] # to set the distance between rows self.row_scale = 2.3 - def get_bed_handler(self): + def get_bed_handler(self, plot_regions=None): + if not self.properties['global_max_row']: + # I do the intersection: + file_to_open = temp_file_from_intersect(self.properties['file'], + plot_regions, AROUND_REGION) + else: + file_to_open = self.properties['file'] # To remove in next 1.0 if self.properties['file'].endswith('gtf') or \ self.properties['file'].endswith('gtf.gz'): self.log.warning("Deprecation Warning: " - "In section {}, file_type was set to {}" + f"In section {self.properties['section_name']}," + f" file_type was set to {self.TRACK_TYPE}" " whereas it is a gtf file. In the future" " only bed files will be accepted, please" - " use file_type = gtf." - "".format(self.properties['section_name'], - self.TRACK_TYPE)) - bed_file_h = ReadGtf(self.properties['file'], + " use file_type = gtf.\n") + bed_file_h = ReadGtf(file_to_open, self.properties['prefered_name'], self.properties['merge_transcripts']) total_length = bed_file_h.length else: # end of remove - total_length = count_lines(opener(self.properties['file']), + total_length = count_lines(opener(file_to_open), asBed=True) - bed_file_h = ReadBed(opener(self.properties['file'])) + bed_file_h = ReadBed(opener(file_to_open)) return(bed_file_h, total_length) - def process_bed(self): + def process_bed(self, plot_regions=None): - bed_file_h, total_length = self.get_bed_handler() + bed_file_h, total_length = self.get_bed_handler(plot_regions) self.bed_type = bed_file_h.file_type if self.properties['color'] == 'bed_rgb' and \ self.bed_type not in ['bed12', 'bed9']: self.log.warning("*WARNING* Color set to 'bed_rgb', " "but bed file does not have the rgb field. " - "The color has been set to {}".format(DEFAULT_BED_COLOR)) + f"The color has been set to {DEFAULT_BED_COLOR}.\n") self.properties['color'] = DEFAULT_BED_COLOR valid_intervals = 0 @@ -279,7 +284,7 @@ def process_bed(self): if valid_intervals == 0: self.log.warning("No valid intervals were found in file " - "{}".format(self.properties['file'])) + f"{self.properties['file']}.\n") return interval_tree, min_score, max_score @@ -318,7 +323,7 @@ def get_max_num_row(self, len_w, small_relative): if free_row > self.max_num_row[bed.chromosome]: self.max_num_row[bed.chromosome] = free_row - self.log.debug("max number of rows set to {}".format(self.max_num_row)) + self.log.debug(f"max number of rows set to {self.max_num_row}") return self.max_num_row def get_y_pos(self, free_row): @@ -353,11 +358,13 @@ def get_y_pos(self, free_row): def plot(self, ax, chrom_region, start_region, end_region): if chrom_region not in self.interval_tree.keys(): chrom_region_before = chrom_region - chrom_region = self.change_chrom_names(chrom_region) + chrom_region = change_chrom_names(chrom_region) if chrom_region not in self.interval_tree.keys(): - self.log.warning("*Warning*\nNeither " + chrom_region_before - + " nor " + chrom_region + " existss as a " - "chromosome name inside the bed file. " + self.log.warning("*Warning*\nNo interval was found when " + "overlapping with both " + f"{chrom_region_before}:{start_region - AROUND_REGION}-{end_region + AROUND_REGION}" + f" and {chrom_region}:{start_region - AROUND_REGION}-{end_region + AROUND_REGION}" + " inside the bed file. " "This will generate an empty track!!\n") return chrom_region = self.check_chrom_str_bytes(self.interval_tree, @@ -549,26 +556,26 @@ def is_right_to(a, b): verticalalignment='center', fontproperties=self.fp) if self.counter == 0: - self.log.warning("*Warning* No intervals were found for file {} " - "in section '{}' for the interval plotted" - " ({}:{}-{}).\n". - format(self.properties['file'], - self.properties['section_name'], - chrom_region, start_region, end_region)) + self.log.warning("*Warning* No intervals were found for file" + f" {self.properties['file']} in " + f"section '{self.properties['section_name']}'" + " for the interval plotted" + f" ({chrom_region}:{start_region}-{end_region}).\n") epsilon = 0.08 ymax = - epsilon + # We set ymin and ymax to have genes centered epsilon from the border + if self.properties['global_max_row']: - ymin = self.max_num_row[chrom_region] * self.row_scale + max_ypos = self.max_num_row[chrom_region] * self.row_scale elif self.properties['gene_rows'] is not None: - ymin = self.properties['gene_rows'] * self.row_scale + max_ypos = self.properties['gene_rows'] * self.row_scale - else: - ymin = max_ypos + (1 + epsilon) + ymin = max_ypos + (1 + epsilon) - self.log.debug("ylim {},{}".format(ymin, ymax)) + self.log.debug(f"ylim {ymin},{ymax}") # the axis is inverted (thus, ymax < ymin) ax.set_ylim(ymin, ymax) @@ -1017,7 +1024,7 @@ def plot_triangles(self, ax, genes_overlap): ymax = y2 if valid_regions == 0: - self.log.warning("No regions found for section {}.".format(self.properties['section_name'])) + self.log.warning(f"No regions found for section {self.properties['section_name']}.\n") if self.properties['orientation'] == 'inverted': ax.set_ylim(ymax, 0) diff --git a/pygenometracks/tracks/BigWigTrack.py b/pygenometracks/tracks/BigWigTrack.py index 7f0db244..e51835c2 100644 --- a/pygenometracks/tracks/BigWigTrack.py +++ b/pygenometracks/tracks/BigWigTrack.py @@ -1,6 +1,6 @@ from . GenomeTrack import GenomeTrack import numpy as np -from .. utilities import plot_coverage, InputError, transform +from .. utilities import plot_coverage, InputError, transform, change_chrom_names import pyBigWig DEFAULT_BIGWIG_COLOR = '#33a02c' @@ -9,16 +9,19 @@ class BigWigTrack(GenomeTrack): SUPPORTED_ENDINGS = ['.bw', '.bigwig'] TRACK_TYPE = 'bigwig' - OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + """ + OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + f""" color = #666666 +# To use a different color for negative values +#negative_color = red # To use transparency, you can use alpha # default is 1 # alpha = 0.5 # the default for min_value and max_value is 'auto' which means that the scale will go -# from the minimum value found in the region plotted to the maximum value found. +# roughly from the minimum value found in the region plotted to the maximum value found. min_value = 0 #max_value = auto -# The number of bins takes the region to be plotted and divides it into the number of bins specified +# The number of bins takes the region to be plotted and divides it +# into the number of bins specified # Then, at each bin the bigwig mean value is computed and plotted. # A lower number of bins produces a coarser tracks number_of_bins = 700 @@ -61,8 +64,10 @@ class BigWigTrack(GenomeTrack): # gives the transformed values, if you prefer to see # the original values: #y_axis_values = original -file_type = {} - """.format(TRACK_TYPE) +# If you want to have a grid on the y-axis +#grid = true +file_type = {TRACK_TYPE} + """ DEFAULTS_PROPERTIES = {'max_value': None, 'min_value': None, @@ -79,7 +84,8 @@ class BigWigTrack(GenomeTrack): 'log_pseudocount': 0, 'y_axis_values': 'transformed', 'second_file': None, - 'operation': 'file'} + 'operation': 'file', + 'grid': False} NECESSARY_PROPERTIES = ['file'] SYNONYMOUS_PROPERTIES = {'max_value': {'auto': None}, 'min_value': {'auto': None}} @@ -90,7 +96,7 @@ class BigWigTrack(GenomeTrack): 'transform': ['no', 'log', 'log1p', '-log', 'log2', 'log10'], 'y_axis_values': ['original', 'transformed']} - BOOLEAN_PROPERTIES = ['nans_to_zeros', 'show_data_range'] + BOOLEAN_PROPERTIES = ['nans_to_zeros', 'show_data_range', 'grid'] STRING_PROPERTIES = ['file', 'file_type', 'overlay_previous', 'orientation', 'summary_method', 'title', 'color', 'negative_color', @@ -111,9 +117,9 @@ def __init__(self, *args, **kwargs): self.bw2 = None if 'second_file' in self.properties['operation']: if self.properties['second_file'] is None: - raise InputError("operation: {} requires to set the parameter" - " second_file." - "".format(self.properties['operation'])) + raise InputError(f"operation: {self.properties['operation']}" + " requires to set the parameter" + " second_file.") else: self.bw2 = pyBigWig.open(self.properties['second_file']) @@ -134,29 +140,23 @@ def set_properties_defaults(self): "'y_axis_values' was set to 'original'. " "'y_axis_values' can only be set to " "'original' when 'transform' is used.\n" - " It will be set as 'transformed'.") + " It will be set as 'transformed'.\n") self.properties['y_axis_values'] = 'transformed' def plot(self, ax, chrom_region, start_region, end_region): - formated_region = "{}:{}-{}".format(chrom_region, start_region, end_region) if chrom_region not in self.bw.chroms().keys(): chrom_region_before = chrom_region - chrom_region = self.change_chrom_names(chrom_region) + chrom_region = change_chrom_names(chrom_region) if chrom_region not in self.bw.chroms().keys(): self.log.warning("*Warning*\nNeither " + chrom_region_before - + " nor " + chrom_region + " existss as a " + + " nor " + chrom_region + " exists as a " "chromosome name inside the bigwig file. " "This will generate an empty track!!\n") return chrom_region = self.check_chrom_str_bytes(self.bw.chroms().keys(), chrom_region) - if chrom_region not in self.bw.chroms().keys(): - self.log.warning("Can not read region {} from bigwig file:\n\n" - "{}\n\nPlease check that the chromosome name is part of the bigwig file " - "and that the region is valid".format(formated_region, self.properties['file'])) - # on rare occasions pyBigWig may throw an error, apparently caused by a corruption # of the memory. This only occurs when calling trackPlot from different # processors. Reloading the file solves the problem. @@ -173,12 +173,13 @@ def plot(self, ax, chrom_region, start_region, end_region): except Exception as e: self.bw = pyBigWig.open(self.properties['file']) - self.log.warning("error found while reading bigwig scores ({}).\nTrying again. Iter num: {}". - format(e, num_tries)) + self.log.warning("error found while reading bigwig scores " + f"({e}).\nTrying again." + f" Iter num: {num_tries}.\n") pass else: if num_tries > 1: - self.log.warning("After {} the scores could be computed".format(num_tries)) + self.log.warning(f"After {num_tries} the scores could be computed.\n") break x_values = np.linspace(start_region, end_region, self.properties['number_of_bins']) @@ -193,10 +194,9 @@ def plot(self, ax, chrom_region, start_region, end_region): new_scores_per_bin = eval('[' + operation + ' for file in scores_per_bin]') new_scores_per_bin = np.array(new_scores_per_bin) except Exception as e: - raise Exception("The operation in section {} could not be" - " computed: {}". - format(self.properties['section_name'], - e)) + raise Exception("The operation in section " + f"{self.properties['section_name']} could not " + f"be computed: {e}") else: scores_per_bin = new_scores_per_bin else: @@ -204,7 +204,7 @@ def plot(self, ax, chrom_region, start_region, end_region): chrom_region2 = chrom_region if chrom_region2 not in self.bw2.chroms().keys(): chrom_region_before2 = chrom_region2 - chrom_region2 = self.change_chrom_names(chrom_region2) + chrom_region2 = change_chrom_names(chrom_region2) if chrom_region2 not in self.bw2.chroms().keys(): self.log.warning("*Warning*\nNeither " + chrom_region_before2 + " nor " @@ -232,12 +232,12 @@ def plot(self, ax, chrom_region, start_region, end_region): self.log.warning("error found while reading bigwig scores" " of second file" - " ({}).\nTrying again. Iter num: {}". - format(e, num_tries)) + f" ({e}).\nTrying again." + " Iter num: {num_tries}.\n") pass else: if num_tries > 1: - self.log.warning("After {} the scores could be computed".format(num_tries)) + self.log.warning(f"After {num_tries} the scores could be computed.\n") break # compute the operation try: @@ -247,11 +247,9 @@ def plot(self, ax, chrom_region, start_region, end_region): ' scores_per_bin2)]') new_scores_per_bin = np.array(new_scores_per_bin) except Exception as e: - raise Exception("The operation {}, in section {} could not be" - " computed: {}". - format(self.properties['operation'], - self.properties['section_name'], - e)) + raise Exception("The operation in section " + f"{self.properties['section_name']} could not " + f"be computed: {e}") else: scores_per_bin = new_scores_per_bin @@ -264,7 +262,8 @@ def plot(self, ax, chrom_region, start_region, end_region): self.size, self.properties['color'], self.properties['negative_color'], - self.properties['alpha']) + self.properties['alpha'], + self.properties['grid']) ymax = self.properties['max_value'] ymin = self.properties['min_value'] @@ -274,13 +273,13 @@ def plot(self, ax, chrom_region, start_region, end_region): else: ymax = transform(np.array([ymax]), self.properties['transform'], self.properties['log_pseudocount'], - 'ymax') + 'ymax')[0] if ymin is None: ymin = plot_ymin else: ymin = transform(np.array([ymin]), self.properties['transform'], self.properties['log_pseudocount'], - 'ymin') + 'ymin')[0] if self.properties['orientation'] == 'inverted': ax.set_ylim(ymax, ymin) @@ -293,7 +292,8 @@ def plot_y_axis(self, ax, plot_axis): super(BigWigTrack, self).plot_y_axis(ax, plot_axis, self.properties['transform'], self.properties['log_pseudocount'], - self.properties['y_axis_values']) + self.properties['y_axis_values'], + self.properties['grid']) def __del__(self): self.bw.close() diff --git a/pygenometracks/tracks/EpilogosTrack.py b/pygenometracks/tracks/EpilogosTrack.py index 90ea0960..03984fcf 100644 --- a/pygenometracks/tracks/EpilogosTrack.py +++ b/pygenometracks/tracks/EpilogosTrack.py @@ -22,7 +22,7 @@ class EpilogosTrack(BedGraphTrack): """ SUPPORTED_ENDINGS = ['.qcat', '.qcat.bgz'] TRACK_TYPE = 'epilogos' - OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + """ + OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + f""" # The categories file should contain the color information for each category id # A categories file should look like: # {{ @@ -36,10 +36,11 @@ class EpilogosTrack(BedGraphTrack): #}} categories_file = # optional. If not given, it is guessed from the file ending. -file_type = {} - """.format(TRACK_TYPE) +file_type = {TRACK_TYPE} + """ DEFAULTS_PROPERTIES = {'categories_file': None, - 'orientation': None} + 'orientation': None, + 'region': None} # Cannot be set manually but is set by tracksClass NECESSARY_PROPERTIES = ['file'] SYNONYMOUS_PROPERTIES = {} POSSIBLE_PROPERTIES = {'orientation': [None, 'inverted']} diff --git a/pygenometracks/tracks/GenomeTrack.py b/pygenometracks/tracks/GenomeTrack.py index f9512218..13591948 100644 --- a/pygenometracks/tracks/GenomeTrack.py +++ b/pygenometracks/tracks/GenomeTrack.py @@ -25,8 +25,9 @@ class GenomeTrack(object): height = 2 # if you want to plot the track upside-down: # orientation = inverted -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale +# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. +# For the 'share-y' option the y axis values is shared between this plot and the overlay plot. +# Otherwise, each plot use its own scale #overlay_previous = yes """ DEFAULTS_PROPERTIES = {} @@ -54,28 +55,21 @@ def set_properties_defaults(self): for prop in self.DEFAULTS_PROPERTIES: if prop not in self.properties: self.properties[prop] = self.DEFAULTS_PROPERTIES[prop] - # use synonymous: - for prop in self.SYNONYMOUS_PROPERTIES: - synonymous = self.SYNONYMOUS_PROPERTIES[prop] - if prop in self.properties and \ - self.properties[prop] in synonymous: - self.properties[prop] = synonymous[self.properties[prop]] # check if properties are possible: for prop in self.POSSIBLE_PROPERTIES: possibles = self.POSSIBLE_PROPERTIES[prop] if self.properties[prop] not in possibles: default_value = self.DEFAULTS_PROPERTIES[prop] - self.log.warning("*WARNING* {0}: '{1}' for section {2}" - " is not valid. {0} has " + self.log.warning(f"*WARNING* {prop}: '{self.properties[prop]}'" + " for section " + f"{self.properties['section_name']}" + f" is not valid. {prop} has " "been set to " - "{3}".format(prop, - self.properties[prop], - self.properties['section_name'], - default_value)) + f"{default_value}.\n") self.properties[prop] = default_value def plot_y_axis(self, ax, plot_axis, transform='no', log_pseudocount=0, - y_axis='tranformed'): + y_axis='tranformed', only_at_ticks=False): """ Plot the scale of the y axis with respect to the plot_axis Args: @@ -84,6 +78,8 @@ def plot_y_axis(self, ax, plot_axis, transform='no', log_pseudocount=0, transform: what was the transformation of the data log_pseudocount: y_axis: 'tranformed' or 'original' + only_at_ticks: False: only min_max are diplayed + True: only ticks values are displayed Returns: @@ -97,79 +93,130 @@ def value_to_str(value): if value % 1 == 0: str_value = str(int(value)) else: - str_value = "{:.1f}".format(value) + str_value = f"{value:.1f}" return str_value + def untransform(value, transform, log_pseudocount): + # given a numeric value, transform and log_pseudocount + # return the value before the transformation + if transform == 'log': + return np.exp(value) - log_pseudocount + elif transform == 'log2': + return np.exp2(value) - log_pseudocount + elif transform == 'log10': + return np.power(10, value) - log_pseudocount + elif transform == 'log1p': + return np.expm1(value) + elif transform == '-log': + return np.exp(- value) - log_pseudocount + ymin, ymax = plot_axis.get_ylim() + # If the ticks are closer than epsilon from the top or bottom + # The vertical alignment of label is adjusted + epsilon = (ymax - ymin) / 100 + # When the ymax and ymin are plotted (when there is no grid) + # The tick is shifted inside of epsilon_pretty + # To avoid to have only half of the width of the line plotted + epsilon_pretty = epsilon - if transform == 'no' or y_axis == 'transformed': + if only_at_ticks: + # plot something that looks like this: + # tick3 ┐ + # │ + # tick2-| + # │ + # tick1 ┘ + if ymin < ymax: + ticks_values = [t for t in plot_axis.get_yticks() if t <= ymax and t >= ymin] + else: + ticks_values = [t for t in plot_axis.get_yticks() if t >= ymax and t <= ymin] + ticks_values.sort(reverse=True) + labels_pos = ticks_values + if transform == 'no' or y_axis == 'transformed': + ticks_labels = [value_to_str(t) for t in ticks_values] + else: + # There is a transformation and we want to display original values + ticks_labels = [value_to_str(untransform(t, transform, log_pseudocount)) for t in ticks_values] + elif transform == 'no' or y_axis == 'transformed': # This is a linear scale # plot something that looks like this: # ymax ┐ # │ # │ # ymin ┘ - - # the coordinate system used is the ax.transAxes (lower left corner (0,0), upper right corner (1,1) - # this way is easier to adjust the positions such that the lines are plotted complete + # adjust the positions such that the lines are plotted complete # and not only half of the width of the line. - x_pos = [0, 0.5, 0.5, 0] - y_pos = [0.01, 0.01, 0.99, 0.99] + ticks_values = [ymin + epsilon_pretty, ymax - epsilon_pretty] + labels_pos = [ymin, ymax] + ticks_labels = [value_to_str(v) for v in [ymin, ymax]] + if y_axis == 'transformed' and transform != 'no': + if transform == 'log1p': + ymid_str = "log(1 + x)" + else: + if log_pseudocount == 0: + ymid_str = f"{transform}(x)" + else: + ymid_str = f"{transform}({log_pseudocount} + x)" + + ax.text(0, (ymax + ymin) / 2, ymid_str, + verticalalignment='center', + horizontalalignment='right', wrap=True) else: - # ymid is the middle between ymin and ymax - # if 0 is between ymin and ymax then ymid is 0 + # There is a transformation and we want to display original values if ymin * ymax < 0: ymid = 0 - ymid_pos = - ymin / (ymax - ymin) else: ymid = (ymin + ymax) / 2 - ymid_pos = 0.5 - - if transform == 'log': - ymin, ymid, ymax = np.exp([ymin, ymid, ymax]) - log_pseudocount - elif transform == 'log2': - ymin, ymid, ymax = np.exp2([ymin, ymid, ymax]) - \ - log_pseudocount - elif transform == 'log10': - ymin, ymid, ymax = np.power(10, [ymin, ymid, ymax]) - \ - log_pseudocount - elif transform == 'log1p': - ymin, ymid, ymax = np.expm1([ymin, ymid, ymax]) - elif transform == '-log': - ymin, ymid, ymax = np.exp(- [ymin, ymid, ymax]) - \ - log_pseudocount - ymid_str = value_to_str(ymid) # plot something that looks like this: # ymax ┐ # │ # ymid-| # │ # ymin ┘ - x_pos = [0, 0.5, 0.5, 0, 0.5, 0.5, 0] - y_pos = [0.01, 0.01, ymid_pos, ymid_pos, ymid_pos, 0.99, 0.99] - ymax_str = value_to_str(ymax) - ymin_str = value_to_str(ymin) - ax.plot(x_pos, y_pos, color='black', linewidth=1, transform=ax.transAxes) - ax.text(-0.2, -0.01, ymin_str, verticalalignment='bottom', horizontalalignment='right', transform=ax.transAxes) - ax.text(-0.2, 1, ymax_str, verticalalignment='top', horizontalalignment='right', transform=ax.transAxes) - if transform != 'no': - if y_axis == 'original': - ax.text(-0.2, ymid_pos, ymid_str, verticalalignment='center', - horizontalalignment='right', transform=ax.transAxes) - else: - if transform == 'log1p': - ymid_str = "log(1 + x)" - else: - if log_pseudocount == 0: - ymid_str = "{}(x)".format(transform) - else: - ymid_str = "{}({} + x)".format(transform, - log_pseudocount) + ticks_values = [ymin + epsilon_pretty, ymid, ymax - epsilon_pretty] + labels_pos = [ymin, ymid, ymax] + ticks_labels = [value_to_str(untransform(v, transform, log_pseudocount)) for v in [ymin, ymid, ymax]] + + # The lower label should be verticalalignment='bottom' + # if it corresponds to ymin + i = 0 + if (ymin < ymax and ticks_values[i] <= ymin + epsilon) \ + or (ymin > ymax and ticks_values[i] >= ymin + epsilon): + v_al = 'bottom' + adjusted_value = labels_pos[i] - epsilon + else: + v_al = 'center' + adjusted_value = labels_pos[i] + ax.text(-0.2, adjusted_value, ticks_labels[i], + verticalalignment=v_al, horizontalalignment='right') + x_pos = [0, 0.5] + y_pos = [ticks_values[i]] * 2 + for i in range(1, len(ticks_values) - 1): + ax.text(-0.2, labels_pos[i], ticks_labels[i], + verticalalignment='center', + horizontalalignment='right') + x_pos += [0.5, 0, 0.5] + y_pos += [ticks_values[i]] * 3 + + # The upper label should be verticalalignment='top' + # if it corresponds to ymax + i = len(ticks_values) - 1 + if (ymin < ymax and ticks_values[i] >= ymax - epsilon) \ + or (ymin > ymax and ticks_values[i] <= ymax - epsilon): + v_al = 'top' + else: + v_al = 'center' + ax.text(-0.2, labels_pos[i], ticks_labels[i], + verticalalignment=v_al, horizontalalignment='right') + x_pos += [0.5, 0] + y_pos += [ticks_values[i]] * 2 - ax.text(0, 0.5, ymid_str, verticalalignment='center', - horizontalalignment='right', transform=ax.transAxes, - wrap=True) + # Finally plot the line: + ax.plot(x_pos, y_pos, color='black', linewidth=1) + # Set the lims: + ax.set_ylim(plot_axis.get_ylim()) + ax.set_xlim(0, 1) ax.patch.set_visible(False) def plot_label(self, label_ax, width_dpi, h_align='left'): @@ -206,20 +253,18 @@ def process_type_for_coverage_track(self): try: self.size = float(size) except ValueError: - self.log.warning("Invalid value: 'type = {}' in section: {}\n" + self.log.warning("Invalid value: 'type = " + f"{self.properties['type']}' in section:" + f" {self.properties['section_name']}\n" "A number was expected after ':' and found " - "'{}'. Will use default." - "".format(self.properties['type'], - self.properties['section_name'], - size)) + f"'{size}'. Will use default.\n") else: self.plot_type = self.properties['type'] if self.plot_type not in ['line', 'points', 'fill']: - self.log.warning("Invalid: 'type = {}' in section: {}\n" - "Will use default." - "".format(self.properties['type'], - self.properties['section_name'])) + self.log.warning(f"Invalid: 'type = {self.properties['type']}' in" + f" section: {self.properties['section_name']}\n" + "Will use default.\n") self.plot_type = default_plot_type def process_color(self, param, colormap_possible=False, @@ -248,36 +293,33 @@ def process_color(self, param, colormap_possible=False, elif self.properties[param][0] == '(': try: custom_color = eval(self.properties[param]) - except ValueError: - self.log.warning("*WARNING* {}: '{}' for section {}" - " is not valid. {} has " + except (SyntaxError, NameError) as e: + self.log.warning(f"*WARNING*: '{param}' for section" + f" {self.properties[param]}" + f" raised an error:\n{e}\n" + f"{self.properties['section_name']} has " "been set to " - "{}".format(param, - self.properties[param], - self.properties['section_name'], - default_value)) + f"{default_value}.\n") valid_color = default_value else: if mc.is_color_like(custom_color): valid_color = custom_color else: - self.log.warning("*WARNING* {}: '{}' for section {}" - " is not valid. {} has " + self.log.warning(f"*WARNING*: '{param}' for section" + f" {self.properties[param]}" + " is not valid. " + f"{self.properties['section_name']} has " "been set to " - "{}".format(param, - self.properties[param], - self.properties['section_name'], - default_value)) + f"{default_value}.\n") valid_color = default_value if not colormap_possible: if valid_color is None: - self.log.warning("*WARNING* {}: '{}' for section {}" - " is not valid. It has " + self.log.warning(f"*WARNING*: '{param}' for section" + f" {self.properties[param]}" + " is not valid. " + f"{self.properties['section_name']} has " "been set to " - "{}".format(param, - self.properties[param], - self.properties['section_name'], - default_value)) + f"{default_value}.\n") valid_color = default_value self.properties[param] = valid_color return False @@ -293,23 +335,25 @@ def process_color(self, param, colormap_possible=False, try: custom_colors = eval(self.properties[param]) except (SyntaxError, NameError) as e: - self.log.warning("Warning: section {}, {} was set as {} but " - "raises an error:\n{}\nIt will be ignored and" - " default value will be used." - "".format(self.properties['section_name'], - param, self.properties[param], - e)) + self.log.warning("Warning: section " + f"{self.properties['section_name']}," + f" {param} was set as " + f"{self.properties[param]} but " + f"raises an error:\n{e}\nIt will be " + "ignored and default value will be " + "used.\n") else: try: valid_colormap = mc.LinearSegmentedColormap.from_list( 'custom', custom_colors, N=100) except ValueError as e: - self.log.warning("Warning: section {}, {} was set as {} but " - "raises an error:\n{}\nIt will be ignored and" - " default value will be used." - "".format(self.properties['section_name'], - param, self.properties[param], - e)) + self.log.warning("Warning: section " + f"{self.properties['section_name']}," + f" {param} was set as " + f"{self.properties[param]} but " + f"raises an error:\n{e}\nIt will " + f"be ignored and" + " default value will be used.\n") else: if self.properties[param] in dir(plt.cm): valid_colormap = self.properties[param] @@ -317,26 +361,22 @@ def process_color(self, param, colormap_possible=False, # valid_color is None or a valid color or the default value # valid_colormap is None or a valid colormap if valid_color is None and valid_colormap is None: - self.log.warning("*WARNING* {}: '{}' for section {}" + self.log.warning(f"*WARNING* {param}: '{self.properties[param]}'" + f" for section {self.properties['section_name']}" " is not valid. It has " "been set to " - "{}".format(param, - self.properties[param], - self.properties['section_name'], - default_value)) + f"{default_value}.\n") self.properties[param] = default_value return default_value_is_colormap if colormap_only: if valid_colormap is None: # valid_color is not None - self.log.warning("*WARNING* {}: '{}' for section {}" - " is not valid: it is a color whereas" - " a colormap was expected. It has " + self.log.warning(f"*WARNING* {param}: " + f"'{self.properties[param]}' for section" + f" {self.properties['section_name']}" + " is not valid. It has " "been set to " - "{}".format(param, - self.properties[param], - self.properties['section_name'], - default_value)) + f"{default_value}.\n") valid_colormap = default_value self.properties[param] = valid_colormap return True @@ -348,22 +388,6 @@ def process_color(self, param, colormap_possible=False, self.properties[param] = valid_colormap return True - @staticmethod - def change_chrom_names(chrom): - """ - Changes UCSC chromosome names to ensembl chromosome names - and vice versa. - """ - # TODO: mapping from chromosome names like mithocondria is missing - if chrom.startswith('chr'): - # remove the chr part from chromosome name - chrom = chrom[3:] - else: - # prefix with 'chr' the chromosome name - chrom = 'chr' + chrom - - return chrom - @staticmethod def check_chrom_str_bytes(iteratable_obj, p_obj): # determine type diff --git a/pygenometracks/tracks/GtfTrack.py b/pygenometracks/tracks/GtfTrack.py index e87d994c..3a1a5220 100644 --- a/pygenometracks/tracks/GtfTrack.py +++ b/pygenometracks/tracks/GtfTrack.py @@ -2,18 +2,20 @@ from . BedTrack import BedTrack from .. readGtf import ReadGtf from matplotlib import font_manager +from .. utilities import temp_file_from_intersect import numpy as np DEFAULT_BED_COLOR = '#1f78b4' DISPLAY_BED_VALID = ['collapsed', 'triangles', 'interleaved', 'stacked'] DISPLAY_BED_SYNONYMOUS = {'interlaced': 'interleaved', 'domain': 'interleaved'} DEFAULT_DISPLAY_BED = 'stacked' +AROUND_REGION = 100000 class GtfTrack(BedTrack): SUPPORTED_ENDINGS = ['gtf', 'gtf.gz'] TRACK_TYPE = 'gtf' - OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + """ + OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + f""" # By default the transcript_name is used. # If you want to use the gene_name: # prefered_name = gene_name @@ -35,21 +37,24 @@ class GtfTrack(BedTrack): # optional: line_width #line_width = 0.5 # the display parameter defines how the gtf file is plotted. -# The options are ['collapsed', 'interleaved', 'triangles'] These options asume that the regions do not overlap. +# Default is 'stacked' where regions are plotted on different lines so +# we can see all regions and all labels. +# The other options are ['collapsed', 'interleaved', 'triangles'] +# These options assume that the regions do not overlap. # `collapsed`: The gtf regions are plotted one after the other in one line. # `interleaved`: The gtf regions are plotted in two lines, first up, then down, then up etc. -# if display is not given, then each region is plotted using the gene style # optional, default is black. To remove the border, simply set 'border_color' to none # Not used in tssarrow style #border_color = black -# style to plot the genes when they have exon information +# style to plot the genes when the display is not triangles #style = UCSC #style = flybase #style = tssarrow # maximum number of gene rows to be plotted. This # field is useful to limit large number of close genes # to be printed over many rows. When several images want -# to be combined this must be set to get equal size, otherwise, on each image the height of each gene changes +# to be combined this must be set to get equal size +# otherwise, on each image the height of each gene changes #gene_rows = 10 # by default the ymax is the number of # rows occupied by the genes in the region plotted. However, @@ -79,12 +84,9 @@ class GtfTrack(BedTrack): # If you want that the tip of the arrow correspond to # the extremity of the interval use: # arrowhead_included = true -# if you want to plot the track on top of the previous track. Options are 'yes' or 'share-y'. For the 'share-y' -# option the y axis values is shared between this plot and the overlay plot. Otherwise, each plot use its own scale -#overlay_previous = yes # optional. If not given is guessed from the file ending. -file_type = {} - """.format(TRACK_TYPE) +file_type = {TRACK_TYPE} + """ DEFAULTS_PROPERTIES = {'fontsize': 12, 'orientation': None, @@ -104,6 +106,7 @@ class GtfTrack(BedTrack): 'color_utr': 'grey', 'height_utr': 1, 'arrow_length': None, + 'region': None, # Cannot be set manually but is set by tracksClass 'all_labels_inside': False, 'labels_in_margin': False} NECESSARY_PROPERTIES = ['file'] @@ -147,8 +150,15 @@ def set_properties_defaults(self): # to set the distance between rows self.row_scale = 2.3 - def get_bed_handler(self): - bed_file_h = ReadGtf(self.properties['file'], + def get_bed_handler(self, plot_regions=None): + if not self.properties['global_max_row']: + # I do the intersection: + file_to_open = temp_file_from_intersect(self.properties['file'], + plot_regions, AROUND_REGION) + else: + file_to_open = self.properties['file'] + + bed_file_h = ReadGtf(file_to_open, self.properties['prefered_name'], self.properties['merge_transcripts']) total_length = bed_file_h.length diff --git a/pygenometracks/tracks/HLinesTrack.py b/pygenometracks/tracks/HLinesTrack.py index e8c8f78e..967ccc98 100644 --- a/pygenometracks/tracks/HLinesTrack.py +++ b/pygenometracks/tracks/HLinesTrack.py @@ -8,12 +8,16 @@ class HLinesTrack(GenomeTrack): SUPPORTED_ENDINGS = [] TRACK_TYPE = 'hlines' - OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + """ + OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + f""" # color of the lines color = black # To use transparency, you can use alpha # default is 1 # alpha = 0.5 +# the default for min_value and max_value is 'auto' which means that the scale will go +# roughly from the minimum value found in the region plotted to the maximum value found. +min_value = 0 +#max_value = auto # line width: # line_width = 0.5 # options for line_style are 'solid', 'dashed', 'dotted', and 'dashdot' @@ -22,8 +26,8 @@ class HLinesTrack(GenomeTrack): y_values = 10, 200 # set show_data_range to false to hide the text on the upper-left showing the data range show_data_range = true -file_type = {} - """.format(TRACK_TYPE) +file_type = {TRACK_TYPE} + """ DEFAULTS_PROPERTIES = {'max_value': None, 'min_value': None, 'show_data_range': True, @@ -56,18 +60,17 @@ def __init__(self, *args, **kwargs): try: self.y_values = [float(x) for x in y_array] except Exception as detail: - raise InputError('y_values ({}) not valid. \nError: {}' - ''.format(self.properties['y_values'], - detail)) + raise InputError(f"y_values ({self.properties['y_values']}) not" + f" valid. \nError: {detail}") def set_properties_defaults(self): super(HLinesTrack, self).set_properties_defaults() self.process_color('color') def plot(self, ax, chrom_region, start_region, end_region): - self.log.debug("y_values: {}".format(self.y_values)) + self.log.debug(f"y_values: {self.y_values}") for y_value in self.y_values: - self.log.debug("y_value: {}".format(y_value)) + self.log.debug(f"y_value: {y_value}") ax.axhline(y=y_value, linewidth=self.properties['line_width'], color=self.properties['color'], diff --git a/pygenometracks/tracks/HiCMatrixTrack.py b/pygenometracks/tracks/HiCMatrixTrack.py index 12812627..5b4a2f42 100644 --- a/pygenometracks/tracks/HiCMatrixTrack.py +++ b/pygenometracks/tracks/HiCMatrixTrack.py @@ -7,6 +7,7 @@ import numpy as np from matplotlib.ticker import LogFormatter from . GenomeTrack import GenomeTrack +from .. utilities import change_chrom_names import logging import itertools @@ -18,9 +19,9 @@ class HiCMatrixTrack(GenomeTrack): SUPPORTED_ENDINGS = ['.h5', '.cool', '.mcool'] TRACK_TYPE = 'hic_matrix' - OPTIONS_TXT = """ -title = -# The different options for color maps can be found here: https://matplotlib.org/users/colormaps.html + OPTIONS_TXT = f""" +# The different options for color maps can be found here: +# https://matplotlib.org/users/colormaps.html # the default color map is RdYlBu_r (_r) stands for reverse # If you want your own colormap you can put the values of the color you want # For example, colormap = ['blue', 'yellow', 'red'] @@ -30,7 +31,8 @@ class HiCMatrixTrack(GenomeTrack): # If it is more than 125% of the plotted region, it will # be adjsted to this maximum value. depth = 100000 -# height of track (in cm) can be given. Otherwise, the height is computed such that the proportions of the +# height of track (in cm) can be given. +# Otherwise, the height is computed such that the proportions of the # hic matrix are kept (e.g. the image does not appear shrink or extended) # height = 10 # min_value and max_value refer to the contacts in the matrix. @@ -43,17 +45,15 @@ class HiCMatrixTrack(GenomeTrack): # the default is to extend neighboring bins to # obtain an aesthetically pleasant output show_masked_bins = false -# if you want to plot the track upside-down: -# orientation = inverted # optional if the values in the matrix need to be scaled the # following parameter can be used. This is useful to plot multiple hic-matrices on the same scale # scale_factor = 1 # You can choose to keep the matrix as not rasterized # (only used if you use pdf or svg output format) by using: # rasterize = false -file_type = {} - """.format(TRACK_TYPE) - DEFAULTS_PROPERTIES = {'region': None, +file_type = {TRACK_TYPE} + """ + DEFAULTS_PROPERTIES = {'region': None, # Cannot be set manually but is set by tracksClass 'depth': 100000, 'orientation': None, 'show_masked_bins': False, @@ -81,31 +81,82 @@ class HiCMatrixTrack(GenomeTrack): def __init__(self, *args, **kwargs): super(HiCMatrixTrack, self).__init__(*args, **kwargs) - log.debug('FILE {}'.format(self.properties)) + log.debug(f'FILE {self.properties}') def set_properties_defaults(self): super(HiCMatrixTrack, self).set_properties_defaults() + # Put default img to None for y axis + self.img = None region = None if self.properties['region'] is not None: - if self.properties['region'][2] == 1e15: - region = [str(self.properties['region'][0])] - elif len(self.properties['region']) == 3: - start = int(self.properties['region'][1]) - self.properties['depth'] - if start < 0: - start = 0 - end = int(self.properties['region'][2]) + self.properties['depth'] - - region = [str(self.properties['region'][0]) + ':' + str(start) + '-' + str(end)] - # try to open with end region + depth to avoid triangle effect in the plot - # if it fails open it with given end region. + # We need to restrict it to a single region because + # HiCMatrix does not accept more + # We check if everything is on a single chrom: + if len(set([r[0] for r in self.properties['region']])) == 1: + chrom = self.properties['region'][0][0] + start = min([r[1] for r in self.properties['region']]) + end = max([r[2] for r in self.properties['region']]) + # I extend of depth to avoid triangle effect in the plot + start = max(0, start - self.properties['depth']) + end += self.properties['depth'] + region = [f"{chrom}:{start}-{end}"] + # Cooler and thus HiCMatrix with cool file will raise an error if: + # - the file is a cool file and: + # - the region goes over the chromosome size + # or + # - the chromosome is not part of the matrix + + # We need to change the log level because we don't want + # the user to see all the errors raised during the try except + logging.getLogger('hicmatrix').setLevel(logging.CRITICAL) try: - self.hic_ma = HiCMatrix.hiCMatrix(self.properties['file'], pChrnameList=region) - except Exception: - region = [str(self.properties['region'][0]) + ':' + str(start) + '-' + str(self.properties['region'][2])] - self.hic_ma = HiCMatrix.hiCMatrix(self.properties['file'], pChrnameList=region) + self.hic_ma = HiCMatrix.hiCMatrix(self.properties['file'], + pChrnameList=region) + except ValueError as ve: + if region is not None: + if "Unknown sequence label" in str(ve): + rs = region[0].split(':') + chrom_region = rs[0] + chrom_region_before = chrom_region + chrom_region = change_chrom_names(chrom_region) + region = [f"{chrom_region}:{rs[1]}"] + try: + self.hic_ma = HiCMatrix.hiCMatrix(self.properties['file'], + pChrnameList=region) + except ValueError as ve2: + if "Unknown sequence label" in str(ve2): + self.log.warning("*Warning*\nNeither " + chrom_region_before + + " nor " + chrom_region + " exists as a " + "chromosome name on the matrix. " + "This will generate an empty track!!\n") + self.hic_ma = HiCMatrix.hiCMatrix() + self.hic_ma.matrix = scipy.sparse.csr_matrix((0, 0)) + elif "Genomic region out of bounds" in str(ve2): + region = [chrom_region] + self.hic_ma = HiCMatrix.hiCMatrix(self.properties['file'], + pChrnameList=region) + else: + raise ve2 + elif "Genomic region out of bounds" in str(ve): + region = [region[0].split(':')[0]] + self.hic_ma = HiCMatrix.hiCMatrix(self.properties['file'], + pChrnameList=region) + else: + raise ve + else: + raise ve + # We put back the log to warning + logging.getLogger('hicmatrix').setLevel(logging.WARNING) if len(self.hic_ma.matrix.data) == 0: - raise Exception("Matrix {} is empty".format(self.properties['file'])) + if region is None: + # This is not due to a restriction of the matrix + raise Exception(f"Matrix {self.properties['file']} is empty") + else: + return + # We need to get the size before masking bins because + # HiCMatrix v13 give smaller chromosome_sizes after: + self.chrom_sizes = self.hic_ma.get_chromosome_sizes() if self.properties['show_masked_bins']: pass else: @@ -117,7 +168,7 @@ def set_properties_defaults(self): if self.hic_ma.matrix.data.min() + 1 <= 0: raise Exception("\n*ERROR*\nMatrix contains values below - 1.\n" "log1p transformation can not be applied to \n" - "values in matrix: {}".format(self.properties['file'])) + f"values in matrix: {self.properties['file']}") elif self.properties['transform'] in ['-log', 'log']: if self.hic_ma.matrix.data.min() < 0: @@ -125,7 +176,7 @@ def set_properties_defaults(self): # mask, they will be replaced by the minimum value after 0. raise Exception("\n*ERROR*\nMatrix contains negative values.\n" "log transformation can not be applied to \n" - "values in matrix: {}".format(self.properties['file'])) + f"values in matrix: {self.properties['file']}") new_intervals = hicmatrix.utilities.enlarge_bins(self.hic_ma.cut_intervals) self.hic_ma.interval_trees, self.hic_ma.chrBinBoundaries = \ @@ -133,7 +184,15 @@ def set_properties_defaults(self): self.hic_ma.cut_intervals = new_intervals binsize = self.hic_ma.getBinSize() + max_depth_in_bins = int(self.properties['depth'] / binsize) + # If the depth is smaller than the binsize. It will display an empty plot + if max_depth_in_bins < 1: + self.log.warning(f"*Warning*\nThe depth({self.properties['depth']})" + f" is smaller than binsize({binsize})" + "This will generate an empty track!!\n") + self.hic_ma.matrix = scipy.sparse.csr_matrix((0, 0)) + return # work only with the lower matrix # and remove all pixels that are beyond @@ -165,28 +224,39 @@ def set_properties_defaults(self): self.cmap.set_bad('black') def plot(self, ax, chrom_region, region_start, region_end): - - log.debug('chrom_region {}, region_start {}, region_end {}'.format(chrom_region, region_start, region_end)) - chrom_sizes = self.hic_ma.get_chromosome_sizes() - if chrom_region not in chrom_sizes: + if len(self.hic_ma.matrix.data) == 0: + self.log.warning("*Warning*\nThere is no data for the region " + "considered on the matrix. " + "This will generate an empty track!!\n") + self.img = None + return + + log.debug(f'chrom_region {chrom_region}, region_start {region_start}, region_end {region_end}') + if chrom_region not in self.chrom_sizes: chrom_region_before = chrom_region - chrom_region = self.change_chrom_names(chrom_region) - if chrom_region not in chrom_sizes: + chrom_region = change_chrom_names(chrom_region) + if chrom_region not in self.chrom_sizes: self.log.warning("*Warning*\nNeither " + chrom_region_before - + " nor " + chrom_region + " existss as a " + + " nor " + chrom_region + " exists as a " "chromosome name on the matrix. " "This will generate an empty track!!\n") + self.img = None return - chrom_region = self.check_chrom_str_bytes(chrom_sizes, chrom_region) - if region_end > chrom_sizes[chrom_region]: - raise Exception("*Error*\nThe region to plot extends beyond the chromosome size. Please check.\n" - "{} size: {}. Region to plot {}-{}\n".format(chrom_region, chrom_sizes[chrom_region], - region_start, region_end)) - - # if self.properties['file'].endswith('.cool'): - # # load now the region to be plotted - # pass + chrom_region = self.check_chrom_str_bytes(self.chrom_sizes, chrom_region) + if region_end > self.chrom_sizes[chrom_region]: + self.log.warning("*Warning*\nThe region to plot extends beyond the" + " chromosome size. Please check.\n" + f"{chrom_region} size: {self.chrom_sizes[chrom_region]}" + f". Region to plot {region_start}-{region_end}\n") + + # A chromosome may disappear if it was full of Nan and nan bins were masked: + if chrom_region not in self.hic_ma.get_chromosome_sizes(): + self.log.warning("*Warning*\nThere is no data for the region " + "considered on the matrix. " + "This will generate an empty track!!\n") + self.img = None + return # expand region to plus depth on both sides # to avoid a 45 degree 'cut' on the edges @@ -194,27 +264,29 @@ def plot(self, ax, chrom_region, region_start, region_end): # get bin id of start and end of region in given chromosome chr_start_id, chr_end_id = self.hic_ma.getChrBinRange(chrom_region) chr_start = self.hic_ma.cut_intervals[chr_start_id][1] - chr_end = self.hic_ma.cut_intervals[chr_end_id - 1][1] + chr_end = self.hic_ma.cut_intervals[chr_end_id - 1][2] start_bp = max(chr_start, region_start - self.properties['depth']) end_bp = min(chr_end, region_end + self.properties['depth']) idx, start_pos = list(zip(*[(idx, x[1]) for idx, x in enumerate(self.hic_ma.cut_intervals) if x[0] == chrom_region and x[1] >= start_bp and x[2] <= end_bp])) - - idx = idx[0:-1] # select only relevant matrix part matrix = self.hic_ma.matrix[idx, :][:, idx] + # update the start_pos to add the last end: + start_pos = tuple(list(start_pos) + [self.hic_ma.cut_intervals[idx[-1]][2]]) # limit the 'depth' based on the length of the region being viewed region_len = region_end - region_start depth = min(self.properties['depth'], int(region_len * 1.25)) - depth_in_bins = int(1.5 * region_len / self.hic_ma.getBinSize()) + # Need to be sure that you keep at least one bin even if the depth is + # smaller than the binsize + depth_in_bins = max(1, int(1.5 * region_len / self.hic_ma.getBinSize())) if depth < self.properties['depth']: - log.warning("The depth was set to {} which is more than 125%" + log.warning(f"The depth was set to {self.properties['depth']} which is more than 125%" " of the region plotted. The depth will be set " - "to {}".format(self.properties['depth'], depth)) + f"to {depth}.\n") # remove from matrix all data points that are not visible. matrix = matrix - scipy.sparse.triu(matrix, k=depth_in_bins, format='csr') # Using todense will replace all nan values by 0. @@ -243,18 +315,22 @@ def plot(self, ax, chrom_region, region_start, region_end): else: # try to use a 'aesthetically pleasant' max value - vmax = np.percentile(matrix.diagonal(1), 80) + try: + vmax = np.percentile(matrix.diagonal(1), 80) + except Exception: + vmax = None if self.properties['min_value'] is not None: vmin = self.properties['min_value'] else: if depth_in_bins > matrix.shape[0]: - depth_in_bins = matrix.shape[0] - 5 + # Make sure you keep one bin + depth_in_bins = max(1, matrix.shape[0] - 5) # if the region length is large with respect to the chromosome length, the diagonal may have # very few values or none. Thus, the following lines reduce the number of bins until the - # diagonal is at least length 5 - num_bins_from_diagonal = int(region_len / self.hic_ma.getBinSize()) + # diagonal is at least length 5 but make sure you have at least one value: + num_bins_from_diagonal = max(1, int(region_len / self.hic_ma.getBinSize())) for num_bins in range(0, num_bins_from_diagonal)[::-1]: distant_diagonal_values = matrix.diagonal(num_bins) if len(distant_diagonal_values) > 5: @@ -262,8 +338,9 @@ def plot(self, ax, chrom_region, region_start, region_end): vmin = np.median(distant_diagonal_values) - self.log.info("setting min, max values for track {} to: {}, {}\n". - format(self.properties['section_name'], vmin, vmax)) + self.log.info("setting min, max values for track " + f"{self.properties['section_name']} to: " + f"{vmin}, {vmax}\n") self.img = self.pcolormesh_45deg(ax, matrix, start_pos, vmax=vmax, vmin=vmin) if self.properties['rasterize']: self.img.set_rasterized(True) @@ -273,6 +350,8 @@ def plot(self, ax, chrom_region, region_start, region_end): ax.set_ylim(0, depth) def plot_y_axis(self, cbar_ax, plot_ax): + if self.img is None: + return if self.properties['transform'] in ['log', 'log1p']: # get a useful log scale diff --git a/pygenometracks/tracks/LinksTrack.py b/pygenometracks/tracks/LinksTrack.py index 44a3aa11..21c2656d 100644 --- a/pygenometracks/tracks/LinksTrack.py +++ b/pygenometracks/tracks/LinksTrack.py @@ -5,14 +5,17 @@ import numpy as np import matplotlib.pyplot as plt from matplotlib.patches import Arc, Polygon +from .. utilities import opener, to_string, change_chrom_names, temp_file_from_intersect +from tqdm import tqdm DEFAULT_LINKS_COLOR = 'blue' +HUGE_NUMBER = 1e15 # Which should be above any chromosome size class LinksTrack(GenomeTrack): SUPPORTED_ENDINGS = ['.arcs', '.arc', '.link', '.links', '.bedpe'] TRACK_TYPE = 'links' - OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + """ + OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + f""" # the file format for links is (tab separated) # chr1 start1 end1 chr2 start2 end2 (score ...) # The score field is optional @@ -22,13 +25,16 @@ class LinksTrack(GenomeTrack): # depending on the value of links_type either 'arcs' or 'triangles' or 'loops' can be plotted. # If arcs, a line will be drawn from the center of the first region (chr1: 150), # to the center of the other region (chr1: 275). -# if triangles, the vertix of the triangle will be drawn at the center between the two points (also the center of -# each position is used) +# if triangles, the vertix of the triangle will be drawn at the center between the two points +# (also the extremity of each position is used) # if loops, a rectangle highlighting the intersection between the 2 regions will be shown # the triangles, and loops options are convenient to overlay over a # Hi-C matrix to highlight the matrix pixel of the highlighted link # For these tracks do not hesitate to put large line_width like 5 or 10. links_type = arcs +# For triangles and arcs, by default the extremities coordinates are used +# To use the middle of start1 and end1 and the middle of start2 and end2 +#use_middle = true # color of the lines color = red # if color is a valid colormap name (like RdYlGn), @@ -56,8 +62,8 @@ class LinksTrack(GenomeTrack): # The unit is bp. This corresponds to the longest arc you will see. # This option is incompatible with compact_arcs_level = 2 #ylim = 100000 -file_type = {} - """.format(TRACK_TYPE) +file_type = {TRACK_TYPE} + """ DEFAULTS_PROPERTIES = {'links_type': 'arcs', 'line_width': None, 'line_style': 'solid', @@ -66,8 +72,10 @@ class LinksTrack(GenomeTrack): 'alpha': 0.8, 'max_value': None, 'min_value': None, + 'region': None, # Cannot be set manually but is set by tracksClass 'ylim': None, - 'compact_arcs_level': '0'} + 'compact_arcs_level': '0', + 'use_middle': False} NECESSARY_PROPERTIES = ['file'] SYNONYMOUS_PROPERTIES = {'max_value': {'auto': None}, 'min_value': {'auto': None}, @@ -77,7 +85,7 @@ class LinksTrack(GenomeTrack): 'line_style': ['solid', 'dashed', 'dotted', 'dashdot'], 'compact_arcs_level': ['0', '1', '2']} - BOOLEAN_PROPERTIES = [] + BOOLEAN_PROPERTIES = ['use_middle'] STRING_PROPERTIES = ['file', 'file_type', 'overlay_previous', 'orientation', 'links_type', 'line_style', 'title', 'color', 'compact_arcs_level'] @@ -93,13 +101,14 @@ class LinksTrack(GenomeTrack): def set_properties_defaults(self): super(LinksTrack, self).set_properties_defaults() self.max_height = None - self.interval_tree, min_score, max_score, has_score = self.process_link_file() + self.interval_tree, min_score, max_score, has_score = self.process_link_file(self.properties['region']) if self.properties['line_width'] is None and not has_score: - self.log.warning("*WARNING* for section {}" + self.log.warning("*WARNING* for section " + f"{self.properties['section_name']}" " no line_width has been set but some " "lines do not have scores." "line_width has been set to " - "0.5".format(self.properties['section_name'])) + "0.5.\n") self.properties['line_width'] = 0.5 self.colormap = None @@ -108,12 +117,12 @@ def set_properties_defaults(self): default_value_is_colormap=False) if is_colormap: if not has_score: - self.log.warning("*WARNING* for section {}" + self.log.warning("*WARNING* for section " + f"{self.properties['section_name']}" " a colormap was chosen but some " "lines do not have scores." "Color has been set to " - "{}".format(self.properties['section_name'], - DEFAULT_LINKS_COLOR)) + f"{DEFAULT_LINKS_COLOR}.\n") self.properties['color'] = DEFAULT_LINKS_COLOR else: self.colormap = self.properties['color'] @@ -132,11 +141,11 @@ def set_properties_defaults(self): if self.properties['compact_arcs_level'] == '2' and \ self.properties['ylim'] is not None: - self.log.warning("*WARNING* for section {}" + self.log.warning("*WARNING* for section " + f"{self.properties['section_name']}" " a ylim was set but " "compact_arcs_level was set to 2." - "ylim will be ignore." - "".format(self.properties['section_name'])) + "ylim will be ignore.\n") self.properties['ylim'] = None def plot(self, ax, chrom_region, region_start, region_end): @@ -151,10 +160,10 @@ def plot(self, ax, chrom_region, region_start, region_end): if chrom_region not in list(self.interval_tree): chrom_region_before = chrom_region - chrom_region = self.change_chrom_names(chrom_region) + chrom_region = change_chrom_names(chrom_region) if chrom_region not in list(self.interval_tree): self.log.warning("*Warning*\nNeither " + chrom_region_before - + " nor " + chrom_region + " existss as a " + + " nor " + chrom_region + " exists as a " "chromosome name inside the link file. " "This will generate an empty track!!\n") return @@ -192,15 +201,12 @@ def plot(self, ax, chrom_region, region_start, region_end): ymax = np.sqrt(self.properties['ylim']) else: ymax = self.properties['ylim'] - self.log.debug("{} were links plotted".format(count)) + self.log.debug(f"{count} were links plotted") if self.properties['orientation'] == 'inverted': ax.set_ylim(ymax, -1) else: ax.set_ylim(-1, ymax) - # I guess this was forgotten - # self.log.debug('title is {}'.format(self.properties['title'])) - def plot_y_axis(self, ax, plot_ax): if self.colormap is not None and self.properties['overlay_previous'] == 'no': self.colormap.set_array([]) @@ -313,76 +319,94 @@ def plot_loops(self, ax, loop): if y2 > self.max_height: self.max_height = y2 - def process_link_file(self): + def process_link_file(self, plot_regions): # the file format expected is similar to file format of links in # circos: # chr1 100 200 chr1 250 300 0.5 # where the last value is a score. + + if plot_regions is None: + file_to_open = self.properties['file'] + else: + # To be sure we do not miss links we will intersect with bed with + # only chromosomes used in plot_regions + plot_regions_adapted = [(chrom, 0, HUGE_NUMBER) for chrom, __, __ in plot_regions] + file_to_open = temp_file_from_intersect(self.properties['file'], + plot_regions_adapted) + valid_intervals = 0 interval_tree = {} line_number = 0 has_score = True max_score = float('-inf') min_score = float('inf') - with open(self.properties['file'], 'r') as file_h: - for line in file_h.readlines(): - line_number += 1 - if line.startswith('browser') or line.startswith('track') or line.startswith('#'): - continue - try: - chrom1, start1, end1, chrom2, start2, end2 = line.strip().split('\t')[:6] - except Exception as detail: - raise InputError('File not valid. The format is chrom1 start1, end1, ' - 'chrom2, start2, end2\nError: {}\n in line\n {}'.format(detail, line)) - try: - score = line.strip().split('\t')[6] - except IndexError: - has_score = False - score = np.nan + file_h = opener(file_to_open) + for line in tqdm(file_h.readlines()): + line_number += 1 + line = to_string(line) + if line.startswith('browser') or line.startswith('track') or line.startswith('#'): + continue + try: + chrom1, start1, end1, chrom2, start2, end2 = line.strip().split('\t')[:6] + except Exception as detail: + raise InputError('File not valid. The format is chrom1' + ' start1, end1, ' + f'chrom2, start2, end2\nError: {detail}\n' + f' in line\n {line}') + if chrom1 != chrom2: + self.log.warning(f"Only links in same chromosome are used. Skipping line\n{line}\n") + continue + try: + score = line.strip().split('\t')[6] + except IndexError: + has_score = False + score = np.nan + + try: + start1 = int(start1) + end1 = int(end1) + start2 = int(start2) + end2 = int(end2) + except ValueError as detail: + raise InputError(f"Error reading line: {line_number}. One of the fields is not " + f"an integer.\nError message: {detail}") + + assert start1 <= end1, f"Error in line #{line_number}, end1 larger than start1 in {line}" + assert start2 <= end2, f"Error in line #{line_number}, end2 larger than start2 in {line}" + + if has_score: try: - start1 = int(start1) - end1 = int(end1) - start2 = int(start2) - end2 = int(end2) + score = float(score) except ValueError as detail: - raise InputError("Error reading line: {}. One of the fields is not " - "an integer.\nError message: {}".format(line_number, detail)) - - assert start1 <= end1, "Error in line #{}, end1 larger than start1 in {}".format(line_number, line) - assert start2 <= end2, "Error in line #{}, end2 larger than start2 in {}".format(line_number, line) - - if has_score: - try: - score = float(score) - except ValueError as detail: - self.log.warning("Warning: reading line: {}. The score is not valid {} will not be used. " - "\nError message: {}".format(line_number, score, detail)) - score = np.nan - has_score = False - else: - if score < min_score: - min_score = score - if score > max_score: - max_score = score - - if chrom1 != chrom2: - self.log.warning("Only links in same chromosome are used. Skipping line\n{}\n".format(line)) - continue - - if chrom1 not in interval_tree: - interval_tree[chrom1] = IntervalTree() - - if start2 < start1: - start1, start2 = start2, start1 - end1, end2 = end2, end1 - + self.log.warning(f"Warning: reading line: {line}. The score is not valid {score} will not be used. " + f"\nError message: {detail}\n") + score = np.nan + has_score = False + else: + if score < min_score: + min_score = score + if score > max_score: + max_score = score + + if chrom1 not in interval_tree: + interval_tree[chrom1] = IntervalTree() + + if start2 < start1: + start1, start2 = start2, start1 + end1, end2 = end2, end1 + + if self.properties['use_middle']: + mid1 = (start1 + end1) / 2 + mid2 = (start2 + end2) / 2 + interval_tree[chrom1].add(Interval(mid1, mid2, [start1, end1, start2, end2, score])) + else: # each interval spans from the smallest start to the largest end interval_tree[chrom1].add(Interval(start1, end2, [start1, end1, start2, end2, score])) - valid_intervals += 1 + valid_intervals += 1 if valid_intervals == 0: - self.log.warning("No valid intervals were found in file {}".format(self.properties['file'])) + self.log.warning(f"No valid intervals were found in file {self.properties['file']}.\n") file_h.close() return(interval_tree, min_score, max_score, has_score) diff --git a/pygenometracks/tracks/NarrowPeakTrack.py b/pygenometracks/tracks/NarrowPeakTrack.py index c02f0b26..fcecb4df 100644 --- a/pygenometracks/tracks/NarrowPeakTrack.py +++ b/pygenometracks/tracks/NarrowPeakTrack.py @@ -15,7 +15,7 @@ class NarrowPeakTrack(BedGraphTrack): SUPPORTED_ENDINGS = ['.narrowPeak'] TRACK_TYPE = 'narrow_peak' - OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + """ + OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + f""" color = #FF000080 #max_value = 0.70 show_data_range = true @@ -33,8 +33,8 @@ class NarrowPeakTrack(BedGraphTrack): width_adjust = 1.5 # optional: line_width #line_width = 0.5 -file_type = {} - """.format(TRACK_TYPE) +file_type = {TRACK_TYPE} + """ DEFAULTS_PROPERTIES = {'orientation': None, 'color': DEFAULT_NARROWPEAK_COLOR, 'max_value': None, @@ -43,6 +43,7 @@ class NarrowPeakTrack(BedGraphTrack): 'use_summit': True, 'width_adjust': 1.5, 'type': 'peak', + 'region': None, # Cannot be set manually but is set by tracksClass 'line_width': 1} NECESSARY_PROPERTIES = ['file'] SYNONYMOUS_PROPERTIES = {'max_value': {'auto': None}} @@ -141,7 +142,7 @@ def plot(self, ax, chrom_region, start_region, end_region): x_pos = start + float(end - start) / 2 y_pos = 0 - max_signal * 0.05 if self.properties['show_labels']: - ax.text(x_pos, y_pos, "{}\np-val:{:.1f}\nq-val:{:.1f}".format(name, p_value, q_value), + ax.text(x_pos, y_pos, f"{name}\np-val:{p_value:.1f}\nq-val:{q_value:.1f}", horizontalalignment='center', size='smaller', verticalalignment='top') collection = PatchCollection(self.patches, facecolor=self.properties['color'], match_original=True) @@ -186,7 +187,7 @@ def value_to_str(value): if value % 1 == 0: str_value = str(int(value)) else: - str_value = "{:.1f}".format(value) + str_value = f"{value:.1f}" return str_value ymin, ymax = plot_axis.get_ylim() diff --git a/pygenometracks/tracks/ScaleBarTrack.py b/pygenometracks/tracks/ScaleBarTrack.py index dba990ee..87ecb35b 100644 --- a/pygenometracks/tracks/ScaleBarTrack.py +++ b/pygenometracks/tracks/ScaleBarTrack.py @@ -10,7 +10,7 @@ class ScaleBarTrack(GenomeTrack): SUPPORTED_ENDINGS = [] TRACK_TYPE = 'scalebar' - OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + """ + OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + f""" # color of the scalebar color = black # To use transparency, you can use alpha @@ -32,8 +32,8 @@ class ScaleBarTrack(GenomeTrack): #where = right # fontsize: default is 12 #fontsize = 10 -file_type = {} - """.format(TRACK_TYPE) +file_type = {TRACK_TYPE} + """ DEFAULTS_PROPERTIES = {'fontsize': 12, 'color': DEFAULT_SCALEBAR_COLOR, 'alpha': 1, @@ -56,9 +56,12 @@ class ScaleBarTrack(GenomeTrack): # The color can only be a color def plot(self, ax, chrom_region, start_region, end_region): + # Get the center from the properties x_center = self.properties['x_center'] if x_center is None: + # Else put it in the middle x_center = (end_region + start_region) / 2 + # Get the size form the properties size = self.properties['size'] if size is None: # We put the size that is less than half the plotted region @@ -72,16 +75,19 @@ def plot(self, ax, chrom_region, start_region, end_region): else: first_char = 1 size = first_char * 10**(len(str(half_plotted_region)) - 1) + # We only plot if it will be visible + if x_center - size / 2 > end_region or x_center + size / 2 < start_region: + return + + # We adjust the unit to make it pretty if size < 1e3: - size_label = "{} bases".format(size) + size_label = f"{size} bases" elif size < 1e6: new_size = size / 1e3 - size_label = "{} kb".format(int(new_size) if new_size.is_integer() - else new_size) + size_label = f"{int(new_size) if new_size.is_integer() else new_size} kb" else: new_size = size / 1e6 - size_label = "{} Mb".format(int(new_size) if new_size.is_integer() - else new_size) + size_label = f"{int(new_size) if new_size.is_integer() else new_size} Mb" # We now draw the |-----| x_left = x_center - size / 2 diff --git a/pygenometracks/tracks/TADsTrack.py b/pygenometracks/tracks/TADsTrack.py index 6d66299f..09a88086 100644 --- a/pygenometracks/tracks/TADsTrack.py +++ b/pygenometracks/tracks/TADsTrack.py @@ -1,4 +1,5 @@ from . BedTrack import BedTrack +from . GenomeTrack import GenomeTrack import numpy as np DEFAULT_BED_COLOR = '#1f78b4' @@ -7,9 +8,28 @@ class TADsTrack(BedTrack): SUPPORTED_ENDINGS = ['.domain', '.domains', '.tad', '.tads'] TRACK_TYPE = 'domains' + OPTIONS_TXT = GenomeTrack.OPTIONS_TXT + f""" +# If the bed file contains a column for color (column 9), then this color can be used by +# setting: +#color = bed_rgb +# if color is a valid colormap name (like RbBlGn), then the score (column 5) is mapped +# to the colormap. +# In this case, the the min_value and max_value for the score can be provided, otherwise +# the maximum score and minimum score found are used. +#color = RdYlBu +#min_value=0 +#max_value=100 +# If the color is simply a color name, then this color is used and the score is not considered. +color = darkblue +# optional: line_width +#line_width = 0.5 +# optional, default is black. To remove the border, simply set 'border_color' to none +#border_color = black +# optional. If not given it is guessed from the file ending. +file_type = {TRACK_TYPE} + """ - DEFAULTS_PROPERTIES = {'fontsize': 12, - 'orientation': None, + DEFAULTS_PROPERTIES = {'orientation': None, 'color': DEFAULT_BED_COLOR, 'border_color': 'black', 'line_width': 0.5, @@ -18,7 +38,8 @@ class TADsTrack(BedTrack): 'merge_transcripts': False, # End to remove 'max_value': None, - 'min_value': None} + 'min_value': None, + 'region': None} # Cannot be set manually but is set by tracksClass NECESSARY_PROPERTIES = ['file'] SYNONYMOUS_PROPERTIES = {'max_value': {'auto': None}, 'min_value': {'auto': None}} @@ -42,3 +63,8 @@ class TADsTrack(BedTrack): def __init__(self, *args, **kwarg): super(TADsTrack, self).__init__(*args, **kwarg) self.properties['display'] = 'triangles' + + def set_properties_defaults(self): + self.properties['fontsize'] = 12 + super(TADsTrack, self).set_properties_defaults() + self.properties['global_max_row'] = False diff --git a/pygenometracks/tracksClass.py b/pygenometracks/tracksClass.py index bc10db07..0c975b88 100644 --- a/pygenometracks/tracksClass.py +++ b/pygenometracks/tracksClass.py @@ -12,7 +12,7 @@ import matplotlib.gridspec import matplotlib.cm import mpl_toolkits.axisartist as axisartist -from . utilities import file_to_intervaltree +from . utilities import file_to_intervaltree, change_chrom_names from collections import OrderedDict from pygenometracks.tracks.GenomeTrack import GenomeTrack from pygenometracks.utilities import InputError @@ -57,7 +57,7 @@ class MultiDict(OrderedDict): def __setitem__(self, key, val): if isinstance(val, OrderedDict): self._unique += 1 - key = "{}. [{}]".format(str(self._unique), key) + key = f"{str(self._unique)}. [{key}]" OrderedDict.__setitem__(self, key, val) @@ -66,7 +66,7 @@ class PlotTracks(object): def __init__(self, tracks_file, fig_width=DEFAULT_FIGURE_WIDTH, fig_height=None, fontsize=None, dpi=None, track_label_width=None, - pRegion=None): + plot_regions=None): self.fig_width = fig_width self.fig_height = fig_height self.dpi = dpi @@ -75,7 +75,7 @@ def __init__(self, tracks_file, fig_width=DEFAULT_FIGURE_WIDTH, self.track_list = None start = self.print_elapsed(None) self.available_tracks = self.get_available_tracks() - self.parse_tracks(tracks_file) + self.parse_tracks(tracks_file, plot_regions=plot_regions) if fontsize: fontsize = fontsize else: @@ -95,14 +95,11 @@ def __init__(self, tracks_file, fig_width=DEFAULT_FIGURE_WIDTH, # initialize each track self.track_obj_list = [] for idx, properties in enumerate(self.track_list): - log.info("initialize {}".format(properties['section_name'])) + log.info(f"initialize {properties['section_name']}") # the track_class is obtained from the available tracks track_class = self.available_tracks[properties['file_type']] - if properties['file_type'] == 'hic_matrix': - properties['region'] = pRegion - self.track_obj_list.append(track_class(properties)) - else: - self.track_obj_list.append(track_class(properties)) + properties['region'] = plot_regions + self.track_obj_list.append(track_class(properties)) log.info("time initializing track(s):") self.print_elapsed(start) @@ -139,6 +136,9 @@ def get_tracks_height(self, start_region=None, end_region=None): """ track_height = [] for i, track_dict in enumerate(self.track_list): + if i == 0 and track_dict['overlay_previous'] != 'no': + log.warning("First track can not have the `overlay_previous` option.\n") + self.track_list[i]['overlay_previous'] = 'no' # if overlay_previous is set to a value other than no # then, skip this track height if track_dict['overlay_previous'] != 'no': @@ -206,8 +206,8 @@ def plot(self, file_name, chrom, start, end, title=None, fig_height = sum(track_height) / \ (DEFAULT_MARGINS['top'] - DEFAULT_MARGINS['bottom']) - log.debug("Figure size in cm is {} x {}. Dpi is set to {}" - "\n".format(self.fig_width, fig_height, self.dpi)) + log.debug(f"Figure size in cm is {self.fig_width} x {fig_height}." + f" Dpi is set to {self.dpi}\n") fig = plt.figure(figsize=self.cm2inch(self.fig_width, fig_height)) fig.subplots_adjust(wspace=0, hspace=0.0, @@ -229,10 +229,7 @@ def plot(self, file_name, chrom, start, end, title=None, skipped_tracks = 0 plot_axis = None for idx, track in enumerate(self.track_obj_list): - log.info("plotting {}".format(track.properties['section_name'])) - if idx == 0 and track.properties['overlay_previous'] != 'no': - log.warning("First track can not have the `overlay_previous` option") - track.properties['overlay_previous'] = 'no' + log.info(f"plotting {track.properties['section_name']}") if track.properties['overlay_previous'] in ['yes', 'share-y']: overlay = True @@ -302,12 +299,11 @@ def plot_vlines(self, axis_list, chrom_region, start_region, end_region): if chrom_region not in list(self.vlines_intval_tree): chrom_region_before = chrom_region - chrom_region = GenomeTrack.change_chrom_names(chrom_region) + chrom_region = change_chrom_names(chrom_region) if chrom_region not in list(self.vlines_intval_tree): - log.warning("*Warning*\nNeither " - + chrom_region_before + " nor " - + chrom_region + " existss as a " - "chromosome name inside the " + log.warning("*Warning*\nNo interval was found when " + f"overlapping with both {chrom_region_before}:{start_region}-{end_region}" + f" and {chrom_region}:{start_region}-{end_region} inside the " "file with vertical lines. " "No vertical lines will be " "plotted!!\n") @@ -326,11 +322,14 @@ def plot_vlines(self, axis_list, chrom_region, start_region, end_region): return - def parse_tracks(self, tracks_file): + def parse_tracks(self, tracks_file, plot_regions=None): """ Parses a configuration file :param tracks_file: file path containing the track configuration + :param plot_regions: a list of tuple [(chrom1, start1, end1), (chrom2, start2, end2)] + on which the data should be loaded + here the vlines :return: array of dictionaries and vlines_file. One dictionary per track """ @@ -354,15 +353,22 @@ def parse_tracks(self, tracks_file): # The only thing to check is the file # There is no other parameters to use. if 'file' not in all_keywords: - raise InputError("The section {} is supposed to be a vline" - " but there is no file." - "".format(section_name)) + raise InputError(f"The section {section_name} is supposed to be a vline" + " but there is no file.") track_options['file'] = parser.get(section_name, 'file') - if len(all_keywords) > 2: - extra_keywords = [k for k in all_keywords - if k not in ['file', 'type']] + if 'line_width' in all_keywords: + try: + track_options['line_width'] = float(parser.get(section_name, 'line_width')) + except ValueError: + raise InputError(f"In section {section_name}, line_width " + f"was set to {parser.get(section_name, 'line_width')}" + " whereas we should have a float " + "value.") + extra_keywords = [k for k in all_keywords + if k not in ['file', 'type', 'line_width']] + if len(extra_keywords) > 0: log.warn("These parameters were specified but will not" - " be used {}".format(' '.join(extra_keywords))) + f" be used {' '.join(extra_keywords)}.\n") self.vlines_properties = \ self.check_file_exists(track_options, tracks_file_path) continue @@ -382,11 +388,10 @@ def parse_tracks(self, tracks_file): track_options['file_type'] = parser.get(section_name, 'file_type') if track_options['file_type'] not in self.available_tracks: - raise InputError("Section {}: the file_type {} does not" - " exists.\npossible file_type are:{}." - "".format(section_name, - track_options['file_type'], - self.available_tracks.keys())) + raise InputError(f"Section {section_name}: the file_type " + f"{track_options['file_type']} does not" + " exists.\npossible file_type are:" + f"{self.available_tracks.keys()}.") track_options['track_class'] = \ self.available_tracks[track_options['file_type']] # Or we guess it from the file: @@ -399,21 +404,21 @@ def parse_tracks(self, tracks_file): track_options['track_class'] = \ self.available_tracks[track_options['file_type']] else: - raise InputError("Section {}: there is no file_type nor file " + raise InputError(f"Section {section_name}: there is no file_type nor file " "specified and it is not a [spacer] nor a " "[x-axis] section. This is not a valid " - "section.".format(section_name)) + "section.") # Now we should have a 'track_class' set. # We can get for it all the necessary and possible keywords track_class = track_options['track_class'] NECESSARY_PROPERTIES = track_class.NECESSARY_PROPERTIES for necessary_name in NECESSARY_PROPERTIES: if necessary_name not in all_keywords: - raise InputError("The section {} is describing a object of" - " type {} but the necessary property {}" - " is not part of the config file." - "".format(section_name, track_class, - necessary_name)) + raise InputError(f"The section {section_name} is " + "describing a object of" + f" type {track_class} but the necessary " + f"property {necessary_name}" + " is not part of the config file.") unused_keys = [] # Now we can proceed with the keywords: for name, value in parser.items(section_name): @@ -421,10 +426,10 @@ def parse_tracks(self, tracks_file): if ' ' in name: old_name = name name = '_'.join(name.split(' ')) - log.warn("Deprecated Warning: The section {} uses" - " parameter {} but there is no more parameter" - " with space in name. Will be substituted by {}." - "".format(section_name, old_name, name)) + log.warn(f"Deprecated Warning: The section {section_name} " + f"uses parameter {old_name} but there is no more " + "parameter with space in name. " + f"Will be substituted by {name}.\n") else: old_name = name # end @@ -445,84 +450,82 @@ def parse_tracks(self, tracks_file): # track_options[name] = parser.getboolean(section_name, # name) except ValueError: - raise InputError("In section {}, {} was set to {}" + raise InputError(f"In section {section_name}, " + f"{old_name} was set to {value}" " whereas we should have a boolean " - "value. Please, use true or false." - "".format(section_name, old_name, - value)) + "value. Please, use true or false.") # In the next 1.0 should be: - # "".format(section_name, name, + # f"{name} was set to {value}" if value.lower() not in ['true', 'false']: log.warning("Deprecation Warning: " - "In section {}, {} was set to {}" + f"In section {section_name}, {name} was " + f"set to {value}" " whereas in the future only" " true and false value will be" - " accepted".format(section_name, name, - value)) + " accepted.\n") elif name in track_class.FLOAT_PROPERTIES: try: track_options[name] = float(value) except ValueError: - raise InputError("In section {}, {} was set to {}" + raise InputError(f"In section {section_name}, {name} " + f"was set to {value}" " whereas we should have a float " - "value.".format(section_name, - name, value)) + "value.") min_value, max_value = track_class.FLOAT_PROPERTIES[name] if track_options[name] < min_value or \ track_options[name] > max_value: - raise InputError("In section {}, {} was set to {}" - " whereas it should be between {} and" - " {}.".format(section_name, name, - value, min_value, - max_value)) + raise InputError(f"In section {section_name}, {name} " + f"was set to {value}" + " whereas it should be between " + f"{min_value} and {max_value}.") elif name in track_class.INTEGER_PROPERTIES: try: track_options[name] = int(value) except ValueError: - raise InputError("In section {}, {} was set to {}" + raise InputError(f"In section {section_name}, {name} " + f"was set to {value}" " whereas we should have an integer " - "value.".format(section_name, - name, value)) + "value.") min_value, max_value = track_class.INTEGER_PROPERTIES[name] if track_options[name] < min_value or \ track_options[name] > max_value: - raise InputError("In section {}, {} was set to {}" - " whereas it should be between {} and" - " {}.".format(section_name, name, - value, min_value, - max_value)) + raise InputError(f"In section {section_name}, {name} " + f"was set to {value}" + " whereas it should be between " + f"{min_value} and {max_value}.") else: unused_keys.append(name) # If there are unused keys they are printed in a warning. if len(unused_keys) > 0: - log.warn("In section {}, these parameters are unused:" - "{}".format(section_name, unused_keys)) + log.warn(f"In section {section_name}, these parameters are " + f"unused:{unused_keys}.\n") # The track_options will be checked for the file paths: track_options = self.check_file_exists(track_options, - tracks_file_path) + tracks_file_path, + track_options['file_type'] == 'hic_matrix') # The 'overlay_previous' is initialized: if 'overlay_previous' not in track_options: track_options['overlay_previous'] = 'no' if track_options['overlay_previous'] not in ['no', 'yes', 'share-y']: - raise InputError("In section {}, overlay_previous was set to {}." - " Possible options are no, yes, share-y" - "".format(section_name, - track_options['overlay_previous'])) + raise InputError(f"In section {section_name}, overlay_previous " + f"was set to {track_options['overlay_previous']}." + " Possible options are no, yes, share-y") # If there is no title: if 'title' not in track_options: track_options['title'] = '' if track_options['overlay_previous'] == 'no' and \ track_options['track_class'] not in [SpacerTrack, XAxisTrack]: - log.warn("title not set for section {}" - "\n".format(track_options['section_name'])) + log.warn("title not set for section " + f"{track_options['section_name']}\n") # The track_options are added to the track_list track_list.append(track_options) # Now that they were all checked self.track_list = track_list if self.vlines_properties: self.vlines_intval_tree, __, __ = \ - file_to_intervaltree(self.vlines_properties['file']) + file_to_intervaltree(self.vlines_properties['file'], + plot_regions) def close_files(self): """ @@ -532,7 +535,7 @@ def close_files(self): track.__del__() @staticmethod - def check_file_exists(track_dict, tracks_path): + def check_file_exists(track_dict, tracks_path, is_hic=False): """ Checks if a file or list of files exists. If the file does not exists tries to check if the file may be relative to the track_file path, @@ -551,26 +554,30 @@ def check_file_exists(track_dict, tracks_path): if file_field_name == 'boundaries_file': log.warn("The boundaries_file is not used anymore" " please use another track with the" - " `overlay_previous` option") + " `overlay_previous` option.\n") # # END file_names = [x for x in track_dict[file_field_name].split(" ") if x != ''] full_path_file_names = [] for file_name in file_names: + if is_hic and not file_name.endswith('.h5'): + file_name_to_check = file_name.split("::")[0] + else: + file_name_to_check = file_name + try: - open(file_name, 'r').close() + open(file_name_to_check, 'r').close() full_path_file_names.append(file_name) except IOError: try: # try to find the file in the same path as the - # the path of the + # track file name_with_tracks_path = tracks_path + "/" + file_name - open(name_with_tracks_path, 'r').close() + name_with_tracks_path_to_check = tracks_path + "/" + file_name_to_check + open(name_with_tracks_path_to_check, 'r').close() full_path_file_names.append(name_with_tracks_path) except IOError: - raise InputError("File in section [{}] " - "not found:\n{}\n\n" - "".format(track_dict['section_name'], - file_name)) + raise InputError(f"File in section [{track_dict['section_name']}] " + f"not found:\n{file_name}\n\n") track_dict[file_field_name] = " ".join(full_path_file_names) return track_dict @@ -599,9 +606,9 @@ def guess_filetype(track_dict, available_tracks): file_type = track_class.TRACK_TYPE if file_type is None: - raise InputError("Section {}: can not identify file type. Please" - " specify the file_type for '{}'" - "".format(track_dict['section_name'], file_)) + raise InputError(f"Section {track_dict['section_name']}: can not " + "identify file type. Please" + " specify the file_type for '{file}'") return file_type @@ -629,7 +636,7 @@ class SpacerTrack(GenomeTrack): POSSIBLE_PROPERTIES = {} BOOLEAN_PROPERTIES = [] STRING_PROPERTIES = ['overlay_previous', - 'title'] + 'title', 'file_type'] FLOAT_PROPERTIES = {'height': [0, np.inf]} INTEGER_PROPERTIES = {} @@ -650,7 +657,7 @@ class XAxisTrack(GenomeTrack): POSSIBLE_PROPERTIES = {'where': ['top', 'bottom']} BOOLEAN_PROPERTIES = [] STRING_PROPERTIES = ['overlay_previous', - 'title', 'where'] + 'title', 'where', 'file_type'] FLOAT_PROPERTIES = {'fontsize': [0, np.inf], 'height': [0, np.inf]} INTEGER_PROPERTIES = {} @@ -661,17 +668,17 @@ def __init__(self, *args, **kwargs): def plot(self, ax, chrom_region, region_start, region_end): ticks = ax.get_xticks() if ticks[-1] - ticks[1] <= 1e3: - labels = ["{:,.0f}".format((x)) + labels = [f"{x:,.0f}" for x in ticks] labels[-2] += " b" elif ticks[-1] - ticks[1] <= 4e5: - labels = ["{:,.0f}".format((x / 1e3)) + labels = [f"{x / 1000.0:,.0f}" for x in ticks] labels[-2] += " Kb" else: - labels = ["{:,.1f} ".format((x / 1e6)) + labels = [f"{x / 1000000.0:,.1f} " for x in ticks] labels[-2] += " Mbp" diff --git a/pygenometracks/updateDOC.sh b/pygenometracks/updateDOC.sh index 120c2c4e..6e0b7145 100644 --- a/pygenometracks/updateDOC.sh +++ b/pygenometracks/updateDOC.sh @@ -10,11 +10,13 @@ python pygenometracks/getAllDefaultsAndPossible.py # As well as a file in rst format for each track echo "All available tracks ==================== + +.. toctree:: + :maxdepth: 1 " > docs/content/all_tracks.rst for f in docs/content/tracks/auto/*_deduced_from_code.txt; do track_name=`basename $f _deduced_from_code.txt` - echo " -:doc:\`tracks/${track_name}\`" >> docs/content/all_tracks.rst + echo " tracks/${track_name}" >> docs/content/all_tracks.rst if [ ! -e docs/content/tracks/${track_name}.rst ]; then echo "$track_name ========== diff --git a/pygenometracks/utilities.py b/pygenometracks/utilities.py index 9f86b1f1..e9df2c8e 100644 --- a/pygenometracks/utilities.py +++ b/pygenometracks/utilities.py @@ -1,8 +1,11 @@ import sys +import os import gzip import numpy as np from tqdm import tqdm from intervaltree import IntervalTree, Interval +import pybedtools +import tempfile import warnings @@ -56,22 +59,64 @@ def opener(filename): return f -def file_to_intervaltree(file_name): +def temp_file_from_intersect(file_name, plot_regions=None, around_region=0): + """ + intersect file_name with the plot_regions +/- around_region + :param file_name: string file name + :param plot_regions:a list of tuple [(chrom1, start1, end1), (chrom2, start2, end2)] + with the region to restrict the data to. + :param around_region: integer with the bp to extend to plot_regions + :return: temporary file with the intersection + """ + file_to_open = file_name + # Check if we can restrict the interval tree to a region: + if plot_regions is not None: + # We use pybedtools to overlap: + original_file = pybedtools.BedTool(file_name) + # We extend the start and end: + plot_regions_ext = [(chrom, max(0, start - around_region), end + around_region) for chrom, start, end in plot_regions] + # We will overlap with both version of chromosome name: + plot_regions_as_bed = '\n'.join([f'{chrom} {start} {end}\n{change_chrom_names(chrom)} {start} {end}' for chrom, start, end in plot_regions_ext]) + regions = pybedtools.BedTool(plot_regions_as_bed, from_string=True) + # Bedtools will put a warning because we are using inconsistent + # nomenclature (with and without chr) + temporary_file = tempfile.NamedTemporaryFile(delete=False) + sys.stderr = open(temporary_file.name, 'w') + try: + file_to_open = original_file.intersect(regions, wa=True, u=True).fn + except pybedtools.helpers.BEDToolsError: + file_to_open = file_name + sys.stderr.close() + sys.stderr = sys.__stderr__ + with open(temporary_file.name, 'r') as f: + temp_std_error = f.readlines() + os.remove(temporary_file.name) + error_lines = [line for line in temp_std_error if 'error' in line.lower()] + if len(error_lines) > 0: + error_lines_printable = '\n'.join(error_lines) + sys.stderr.write("Bedtools intersect raised an error:\n" + f"{error_lines_printable}\n" + "Will not use bedtools.\n") + file_to_open = file_name + return file_to_open + + +def file_to_intervaltree(file_name, plot_regions=None): """ converts a BED like file into a bx python interval tree :param file_name: string file name + :param plot_regions:a list of tuple [(chrom1, start1, end1), (chrom2, start2, end2)] + with the region to restrict the data to. :return: interval tree dictionary. They key is the chromosome/contig name and the value is an IntervalTree. Each of the intervals have as 'value' the fields[3:] if any. """ + file_to_open = temp_file_from_intersect(file_name, plot_regions, 0) # iterate over a BED like file # saving the data into an interval tree # for quick retrieval - file_h = opener(file_name) + file_h = opener(file_to_open) line_number = 0 valid_intervals = 0 - prev_chrom = None - prev_start = -1 - prev_line = None interval_tree = {} min_value = float('Inf') max_value = -float('Inf') @@ -85,27 +130,23 @@ def file_to_intervaltree(file_name): try: chrom, start, end = fields[0:3] except Exception as detail: - msg = "Error reading line: {}\nError message: {}".format(line_number, detail) + msg = f"Error reading line: {line_number}\nError message: {detail}" raise InputError(msg) try: start = int(start) except ValueError as detail: - msg = "Error reading line: {}. The start field is not " \ - "an integer.\nError message: {}".format(line_number, detail) + msg = f"Error reading line: {line_number}. The start field is not " \ + f"an integer.\nError message: {detail}" raise InputError(msg) try: end = int(end) except ValueError as detail: - msg = "Error reading line: {}. The end field is not " \ - "an integer.\nError message: {}".format(line_number, detail) + msg = f"Error reading line: {line_number}. The end field is not " \ + f"an integer.\nError message: {detail}" raise InputError(msg) - if prev_chrom == chrom: - assert prev_start <= start, \ - "Bed file not sorted. Please use a sorted bed file.\n{}{} ".format(prev_line, line) - if chrom not in interval_tree: interval_tree[chrom] = IntervalTree() @@ -124,26 +165,28 @@ def file_to_intervaltree(file_name): except ValueError: pass - assert end > start, "Start position larger or equal than end for line\n{} ".format(line) + assert end > start, f"Start position larger or equal than end for line\n{line} " interval_tree[chrom].add(Interval(start, end, value)) valid_intervals += 1 if valid_intervals == 0: - sys.stderr.write("No valid intervals were found in file {}".format(file_name)) + sys.stderr.write(f"No valid intervals were found in file {file_name}") file_h.close() return interval_tree, min_value, max_value def plot_coverage(ax, x_values, score_list, plot_type, size, color, - negative_color, alpha): + negative_color, alpha, grid): + if grid: + ax.grid(axis='y', zorder=0) if plot_type == 'line': if color == negative_color: ax.plot(x_values, score_list, '-', linewidth=size, color=color, alpha=alpha) else: - warnings.warn('Line plots with a different negative color might not look pretty') + warnings.warn('Line plots with a different negative color might not look pretty.\n') pos_x_values = x_values.copy() pos_x_values[score_list < 0] = np.nan ax.plot(pos_x_values, score_list, '-', linewidth=size, color=color, @@ -175,7 +218,7 @@ def plot_coverage(ax, x_values, score_list, plot_type, size, color, else: if plot_type != 'fill': warnings.warn('The plot type was not part of known types ' - '(fill, line, points) will be fill.') + '(fill, line, points) will be fill.\n') if color == negative_color: ax.fill_between(x_values, score_list, linewidth=0.1, color=color, @@ -202,10 +245,10 @@ def transform(score_list, transform, log_pseudocount, file): elif transform in ['log', 'log2', 'log10']: if np.nanmin(score_list) <= - log_pseudocount: msg = ("\n*ERROR*\ncoverage contains values smaller or equal to" - " - {0}.\n" - "{1}({0} + ) transformation can not be applied to " - "values in file: {2}".format(log_pseudocount, transform, - file)) + f" - {log_pseudocount}.\n" + f"{transform}({log_pseudocount} + ) transformation " + "can not be applied to " + f"values in file: {file}") raise Exception(msg) else: return(eval('np.' + transform + '(log_pseudocount + score_list)')) @@ -213,23 +256,22 @@ def transform(score_list, transform, log_pseudocount, file): if np.nanmin(score_list) <= - 1: msg = ("\n*ERROR*\ncoverage contains values below or equal to - 1.\n" "log1p() transformation can not be applied to " - "values in file: {}".format(file)) + f"values in file: {file}") raise Exception(msg) else: return(np.log1p(score_list)) elif transform == '-log': - if np.nanmax(score_list.max) <= - log_pseudocount: + if np.nanmin(score_list) <= - log_pseudocount: msg = ("\n*ERROR*\ncoverage contains values smaller or equal to" - " - {0}.\n" - "- log( {0} + ) transformation can not be applied" - " to values in file: {1}".format(log_pseudocount, file)) + f" - {log_pseudocount}.\n" + f"- log( {log_pseudocount} + ) transformation can " + f"not be applied to values in file: {file}") raise Exception(msg) else: return(- np.log(log_pseudocount + score_list)) else: - warnings.warn('The transform: {} for file {} is not valid.' - 'will not use any transformation'.format(transform, - file)) + warnings.warn(f"The transform: {transform} for file {file} is not " + "valid. Will not use any transformation.\n") return(score_list) @@ -260,3 +302,19 @@ def count_lines(file_h, asBed=False): n += 1 file_h.close() return(n) + + +def change_chrom_names(chrom): + """ + Changes UCSC chromosome names to ensembl chromosome names + and vice versa. + """ + # TODO: mapping from chromosome names like mithocondria is missing + if chrom.startswith('chr'): + # remove the chr part from chromosome name + chrom = chrom[3:] + else: + # prefix with 'chr' the chromosome name + chrom = 'chr' + chrom + + return chrom diff --git a/requirements.txt b/requirements.txt index efb6a1e5..92c2f103 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,11 @@ numpy >=1.16 -matplotlib =3.1.1 +matplotlib ==3.1.1 intervaltree >=2.1.0 pybigwig >=0.3.16 future >=0.17.0 -hicmatrix >=12 +hicmatrix >=13 pysam >=0.14 gffutils >=0.9 +pybedtools >=0.8.1 tqdm >=4.20 +libopenblas < 0.3.10 diff --git a/setup.py b/setup.py index 44f08df5..b6758cfb 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ def update_version_py(): f = open(os.path.join("pygenometracks", "_version.py"), "w") f.write(VERSION_PY % ver) f.close() - print("set pygenometracks/_version.py to '%s'" % ver) + print(f"set pygenometracks/_version.py to '{ver}'") def get_version(): @@ -80,17 +80,14 @@ def checkProgramIsInstalled(self, program, args, where_to_download, except EnvironmentError: # handle file not found error. # the config file is installed in: - msg = "\n**{0} not found. This " \ - "program is needed for the following "\ - "tools to work properly:\n"\ - " {1}\n"\ - "{0} can be downloaded from here:\n " \ - " {2}\n".format(program, affected_tools, - where_to_download) + msg = (f"\n**{program} not found. This program is needed" + " for the following tools to work properly:\n" + f"{affected_tools}\n{program} can be downloaded" + f" from here:\n{where_to_download}\n") sys.stderr.write(msg) except Exception as e: - sys.stderr.write("Error: {}".format(e)) + sys.stderr.write(f"Error: {e}") install_requires_py = ["numpy >=1.16", @@ -98,10 +95,11 @@ def checkProgramIsInstalled(self, program, args, where_to_download, "intervaltree >=2.1.0", "pyBigWig >=0.3.16", "future >=0.17.0", - "hicmatrix >=12", + "hicmatrix >=13", "pysam >=0.14", "pytest", "gffutils >=0.9", + "pybedtools >=0.8.1", "tqdm >=4.20" ] diff --git a/test_locally.sh b/test_locally.sh new file mode 100644 index 00000000..c0ad868a --- /dev/null +++ b/test_locally.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +source $(dirname $(dirname $(which conda)))/etc/profile.d/conda.sh + +for TRAVIS_PYTHON_VERSION in 3.6 3.7; do + conda create -n pgt_test_${TRAVIS_PYTHON_VERSION} --yes -c bioconda -c conda-forge python=$TRAVIS_PYTHON_VERSION --file requirements.txt + conda activate pgt_test_${TRAVIS_PYTHON_VERSION} + # Keeping libopenblas=0.3.10 gives me segmentation fault + conda install --yes -c conda-forge -c bioconda libopenblas=0.3.9 + conda install --yes -c conda-forge -c bioconda pytest ghostscript coverage coverage-badge + python setup.py install + coverage run -m py.test + coverage html + coverage-badge -f -o docs/coverage.svg + conda deactivate +done + +TRAVIS_PYTHON_VERSION=3.8 +conda create -n pgt_test_${TRAVIS_PYTHON_VERSION} --yes -c bioconda -c conda-forge python=$TRAVIS_PYTHON_VERSION +conda activate pgt_test_${TRAVIS_PYTHON_VERSION} +conda install --yes -c conda-forge -c bioconda bedtools pytest ghostscript +pip install -r requirements.txt +python setup.py install +py.test pygenometracks --doctest-modules +conda deactivate