gsrap 0.7.1__tar.gz → 0.7.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. {gsrap-0.7.1 → gsrap-0.7.2}/PKG-INFO +3 -1
  2. {gsrap-0.7.1 → gsrap-0.7.2}/pyproject.toml +4 -1
  3. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/.ipynb_checkpoints/__init__-checkpoint.py +3 -1
  4. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/__init__.py +3 -1
  5. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/.ipynb_checkpoints/excelhub-checkpoint.py +27 -3
  6. gsrap-0.7.2/src/gsrap/commons/.ipynb_checkpoints/figures-checkpoint.py +105 -0
  7. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/excelhub.py +27 -3
  8. gsrap-0.7.2/src/gsrap/commons/figures.py +105 -0
  9. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/.ipynb_checkpoints/mkmodel-checkpoint.py +1 -1
  10. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/mkmodel.py +1 -1
  11. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/.ipynb_checkpoints/completeness-checkpoint.py +96 -63
  12. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/.ipynb_checkpoints/parsedb-checkpoint.py +3 -4
  13. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/completeness.py +96 -63
  14. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/parsedb.py +3 -4
  15. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/.ipynb_checkpoints/simplegrowth-checkpoint.py +2 -2
  16. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/simplegrowth.py +2 -2
  17. {gsrap-0.7.1 → gsrap-0.7.2}/LICENSE.txt +0 -0
  18. {gsrap-0.7.1 → gsrap-0.7.2}/README.md +0 -0
  19. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/assets/.ipynb_checkpoints/PM1-checkpoint.csv +0 -0
  20. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/assets/.ipynb_checkpoints/PM2A-checkpoint.csv +0 -0
  21. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/assets/.ipynb_checkpoints/PM3B-checkpoint.csv +0 -0
  22. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/assets/.ipynb_checkpoints/PM4A-checkpoint.csv +0 -0
  23. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/assets/PM1.csv +0 -0
  24. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/assets/PM2A.csv +0 -0
  25. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/assets/PM3B.csv +0 -0
  26. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/assets/PM4A.csv +0 -0
  27. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/assets/__init__.py +0 -0
  28. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/assets/kegg_compound_to_others.pickle +0 -0
  29. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/assets/kegg_reaction_to_others.pickle +0 -0
  30. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/.ipynb_checkpoints/__init__-checkpoint.py +0 -0
  31. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/.ipynb_checkpoints/biomass-checkpoint.py +0 -0
  32. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/.ipynb_checkpoints/coeffs-checkpoint.py +0 -0
  33. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/.ipynb_checkpoints/downloads-checkpoint.py +0 -0
  34. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/.ipynb_checkpoints/escherutils-checkpoint.py +0 -0
  35. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/.ipynb_checkpoints/fluxbal-checkpoint.py +0 -0
  36. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/.ipynb_checkpoints/logutils-checkpoint.py +0 -0
  37. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/.ipynb_checkpoints/medium-checkpoint.py +0 -0
  38. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/.ipynb_checkpoints/metrics-checkpoint.py +0 -0
  39. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/.ipynb_checkpoints/sbmlutils-checkpoint.py +0 -0
  40. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/__init__.py +0 -0
  41. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/biomass.py +0 -0
  42. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/coeffs.py +0 -0
  43. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/downloads.py +0 -0
  44. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/escherutils.py +0 -0
  45. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/fluxbal.py +0 -0
  46. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/logutils.py +0 -0
  47. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/medium.py +0 -0
  48. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/metrics.py +0 -0
  49. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/commons/sbmlutils.py +0 -0
  50. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/getmaps/.ipynb_checkpoints/__init__-checkpoint.py +0 -0
  51. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/getmaps/.ipynb_checkpoints/getmaps-checkpoint.py +0 -0
  52. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/getmaps/.ipynb_checkpoints/kdown-checkpoint.py +0 -0
  53. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/getmaps/__init__.py +0 -0
  54. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/getmaps/getmaps.py +0 -0
  55. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/getmaps/kdown.py +0 -0
  56. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/.ipynb_checkpoints/__init__-checkpoint.py +0 -0
  57. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/.ipynb_checkpoints/biologcuration-checkpoint.py +0 -0
  58. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/.ipynb_checkpoints/gapfill-checkpoint.py +0 -0
  59. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/.ipynb_checkpoints/gapfillutils-checkpoint.py +0 -0
  60. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/.ipynb_checkpoints/polishing-checkpoint.py +0 -0
  61. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/.ipynb_checkpoints/pruner-checkpoint.py +0 -0
  62. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/__init__.py +0 -0
  63. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/biologcuration.py +0 -0
  64. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/gapfill.py +0 -0
  65. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/gapfillutils.py +0 -0
  66. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/polishing.py +0 -0
  67. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/mkmodel/pruner.py +0 -0
  68. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/.ipynb_checkpoints/__init__-checkpoint.py +0 -0
  69. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/.ipynb_checkpoints/annotation-checkpoint.py +0 -0
  70. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/.ipynb_checkpoints/introduce-checkpoint.py +0 -0
  71. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/.ipynb_checkpoints/manual-checkpoint.py +0 -0
  72. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/.ipynb_checkpoints/repeating-checkpoint.py +0 -0
  73. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/__init__.py +0 -0
  74. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/annotation.py +0 -0
  75. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/introduce.py +0 -0
  76. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/manual.py +0 -0
  77. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/parsedb/repeating.py +0 -0
  78. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/.ipynb_checkpoints/__init__-checkpoint.py +0 -0
  79. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/.ipynb_checkpoints/biosynth-checkpoint.py +0 -0
  80. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/.ipynb_checkpoints/cnps-checkpoint.py +0 -0
  81. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/.ipynb_checkpoints/essentialgenes-checkpoint.py +0 -0
  82. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/.ipynb_checkpoints/growthfactors-checkpoint.py +0 -0
  83. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/.ipynb_checkpoints/precursors-checkpoint.py +0 -0
  84. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/.ipynb_checkpoints/runsims-checkpoint.py +0 -0
  85. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/.ipynb_checkpoints/singleomission-checkpoint.py +0 -0
  86. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/__init__.py +0 -0
  87. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/biosynth.py +0 -0
  88. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/cnps.py +0 -0
  89. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/essentialgenes.py +0 -0
  90. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/growthfactors.py +0 -0
  91. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/precursors.py +0 -0
  92. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/runsims.py +0 -0
  93. {gsrap-0.7.1 → gsrap-0.7.2}/src/gsrap/runsims/singleomission.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: gsrap
3
- Version: 0.7.1
3
+ Version: 0.7.2
4
4
  Summary:
5
5
  License: GNU General Public License v3.0
6
6
  Author: Gioele Lazzari
@@ -17,9 +17,11 @@ Requires-Dist: cobra (>=0.29)
17
17
  Requires-Dist: colorlog (>=6.9.0)
18
18
  Requires-Dist: gdown (>=5.2.0)
19
19
  Requires-Dist: gempipe (>=1.38.1)
20
+ Requires-Dist: matplotlib (>=3.9.0)
20
21
  Requires-Dist: memote (>=0.17.0)
21
22
  Requires-Dist: openpyxl (>=3.1.0)
22
23
  Requires-Dist: pandas (>=2.0.0)
24
+ Requires-Dist: xlsxwriter (>=3.1.0)
23
25
  Description-Content-Type: text/markdown
24
26
 
25
27
  Source code for `gsrap`.
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "gsrap"
3
- version = "0.7.1"
3
+ version = "0.7.2"
4
4
  description = ""
5
5
  authors = ["Gioele Lazzari"]
6
6
  license = "GNU General Public License v3.0"
@@ -16,6 +16,9 @@ gempipe = ">=1.38.1"
16
16
  gdown = ">=5.2.0"
17
17
  colorlog = ">=6.9.0"
18
18
  memote = ">=0.17.0"
19
+ matplotlib = ">=3.9.0"
20
+ xlsxwriter = ">=3.1.0"
21
+
19
22
 
20
23
  [build-system]
21
24
  requires = ["poetry-core>=1.0.0"]
@@ -72,9 +72,9 @@ def main():
72
72
  parsedb_parser.add_argument("--precursors", action='store_true', help="Verify biosynthesis of biomass precursors and show blocked ones.")
73
73
  parsedb_parser.add_argument("--biosynth", action='store_true', help="Check biosynthesis of all metabolites and detect dead-ends.")
74
74
  parsedb_parser.add_argument("-e", "--eggnog", nargs='+', metavar='', type=str, default='-', help="Path to the optional eggnog-mapper annotation table(s).")
75
- #parsedb_parser.add_argument("-z", "--zeroes", action='store_true', help="Show maps/modules with 0%% coverage, in addition to partials (use only with --progress).")
76
75
  parsedb_parser.add_argument("--goodbefore", metavar='', type=str, default='-', help="Syntax is {pure_mid}-{rid1}-{rid2}. From top to bottom, build the universe until reaction {rid1}, transport {rid2} and metabolite {pure_mid} are reached.")
77
76
  parsedb_parser.add_argument("--onlyauthor", metavar='', type=str, default='-', help="Build the universe by parsing contents of the specified author ID only. Contents affected by --goodbefore are parsed anyway.")
77
+ parsedb_parser.add_argument("--nofigs", action='store_true', help="Do not generate figures.")
78
78
 
79
79
 
80
80
  # add arguments for the 'mkmodel' command
@@ -94,6 +94,7 @@ def main():
94
94
  mkmodel_parser.add_argument("--conditional", metavar='', type=float, default=0.5, help="Expected minimum fraction of reactions in a biosynthetic pathway for an actually present conditional biomass precursor.")
95
95
  mkmodel_parser.add_argument("--biosynth", action='store_true', help="Check biosynthesis of all metabolites and detect dead-ends.")
96
96
  mkmodel_parser.add_argument("-b", "--biomass", metavar='', type=str, default='-', help="Strain ID associated to experimental biomass data.")
97
+ mkmodel_parser.add_argument("--nofigs", action='store_true', help="Do not generate figures.")
97
98
 
98
99
 
99
100
  # add arguments for the 'runsims' command
@@ -110,6 +111,7 @@ def main():
110
111
  runsims_parser.add_argument("--omission", action='store_true', help="Perform single omission experiments to study auxotrophies.")
111
112
  runsims_parser.add_argument("--essential", action='store_true', help="Predict essential genes (single-gene knock-out simulations).")
112
113
  runsims_parser.add_argument("--factors", action='store_true', help="Predict putative growth factors.")
114
+ runsims_parser.add_argument("--nofigs", action='store_true', help="Do not generate figures.")
113
115
 
114
116
 
115
117
  # check the inputted subcommand, automatic sys.exit(1) if a bad subprogram was specied.
@@ -72,9 +72,9 @@ def main():
72
72
  parsedb_parser.add_argument("--precursors", action='store_true', help="Verify biosynthesis of biomass precursors and show blocked ones.")
73
73
  parsedb_parser.add_argument("--biosynth", action='store_true', help="Check biosynthesis of all metabolites and detect dead-ends.")
74
74
  parsedb_parser.add_argument("-e", "--eggnog", nargs='+', metavar='', type=str, default='-', help="Path to the optional eggnog-mapper annotation table(s).")
75
- #parsedb_parser.add_argument("-z", "--zeroes", action='store_true', help="Show maps/modules with 0%% coverage, in addition to partials (use only with --progress).")
76
75
  parsedb_parser.add_argument("--goodbefore", metavar='', type=str, default='-', help="Syntax is {pure_mid}-{rid1}-{rid2}. From top to bottom, build the universe until reaction {rid1}, transport {rid2} and metabolite {pure_mid} are reached.")
77
76
  parsedb_parser.add_argument("--onlyauthor", metavar='', type=str, default='-', help="Build the universe by parsing contents of the specified author ID only. Contents affected by --goodbefore are parsed anyway.")
77
+ parsedb_parser.add_argument("--nofigs", action='store_true', help="Do not generate figures.")
78
78
 
79
79
 
80
80
  # add arguments for the 'mkmodel' command
@@ -94,6 +94,7 @@ def main():
94
94
  mkmodel_parser.add_argument("--conditional", metavar='', type=float, default=0.5, help="Expected minimum fraction of reactions in a biosynthetic pathway for an actually present conditional biomass precursor.")
95
95
  mkmodel_parser.add_argument("--biosynth", action='store_true', help="Check biosynthesis of all metabolites and detect dead-ends.")
96
96
  mkmodel_parser.add_argument("-b", "--biomass", metavar='', type=str, default='-', help="Strain ID associated to experimental biomass data.")
97
+ mkmodel_parser.add_argument("--nofigs", action='store_true', help="Do not generate figures.")
97
98
 
98
99
 
99
100
  # add arguments for the 'runsims' command
@@ -110,6 +111,7 @@ def main():
110
111
  runsims_parser.add_argument("--omission", action='store_true', help="Perform single omission experiments to study auxotrophies.")
111
112
  runsims_parser.add_argument("--essential", action='store_true', help="Predict essential genes (single-gene knock-out simulations).")
112
113
  runsims_parser.add_argument("--factors", action='store_true', help="Predict putative growth factors.")
114
+ runsims_parser.add_argument("--nofigs", action='store_true', help="Do not generate figures.")
113
115
 
114
116
 
115
117
  # check the inputted subcommand, automatic sys.exit(1) if a bad subprogram was specied.
@@ -1,8 +1,20 @@
1
1
  import pandas as pnd
2
2
 
3
3
 
4
+ from .figures import figure_df_C_F1
4
5
 
5
- def write_excel_model(model, filepath, df_E, df_B, df_P, df_S):
6
+
7
+
8
+ def write_excel_model(model, filepath, nofigs, df_E, df_B, df_P, df_S, df_C=None):
9
+
10
+
11
+ # generate figures
12
+ if nofigs == False:
13
+
14
+ if df_C is not None:
15
+ df_C_F1 = figure_df_C_F1(df_C)
16
+
17
+
6
18
 
7
19
  df_M = []
8
20
  df_R = []
@@ -33,6 +45,12 @@ def write_excel_model(model, filepath, df_E, df_B, df_P, df_S):
33
45
  df_S.insert(0, 'mid', '') # new columns as first
34
46
  df_S['mid'] = df_S.index
35
47
  df_S = df_S.reset_index(drop=True)
48
+
49
+ # format df_C: universal reaction coverage
50
+ if df_C is not None:
51
+ df_C.insert(0, 'kr', '') # new columns as first
52
+ df_C['kr'] = df_C.index
53
+ df_C = df_C.reset_index(drop=True)
36
54
 
37
55
 
38
56
  for m in model.metabolites:
@@ -81,7 +99,7 @@ def write_excel_model(model, filepath, df_E, df_B, df_P, df_S):
81
99
  df_R = pnd.DataFrame.from_records(df_R)
82
100
  df_T = pnd.DataFrame.from_records(df_T)
83
101
  df_A = pnd.DataFrame.from_records(df_A)
84
- with pnd.ExcelWriter(filepath) as writer:
102
+ with pnd.ExcelWriter(filepath, engine='xlsxwriter') as writer:
85
103
  df_M.to_excel(writer, sheet_name='Metabolites', index=False)
86
104
  df_R.to_excel(writer, sheet_name='Reactions', index=False)
87
105
  df_T.to_excel(writer, sheet_name='Transporters', index=False)
@@ -90,7 +108,12 @@ def write_excel_model(model, filepath, df_E, df_B, df_P, df_S):
90
108
  if df_B is not None: df_B.to_excel(writer, sheet_name='Biomass', index=False)
91
109
  if df_P is not None and len(df_P)!=0: df_P.to_excel(writer, sheet_name='Biolog®', index=False)
92
110
  if df_S is not None and len(df_S.columns)>2: df_S.to_excel(writer, sheet_name='Biosynth', index=False)
93
-
111
+ if df_C is not None:
112
+ df_C.to_excel(writer, sheet_name='Coverage', index=False)
113
+ if nofigs == False:
114
+ worksheet = writer.sheets['Coverage']
115
+ worksheet.insert_image('A1', 'df_C_F1.png', {'image_data': df_C_F1})
116
+
94
117
 
95
118
  sheets_dict = {
96
119
  'model_id': model.id,
@@ -102,6 +125,7 @@ def write_excel_model(model, filepath, df_E, df_B, df_P, df_S):
102
125
  'Biomass': df_B,
103
126
  'Biolog': df_P,
104
127
  'Biosynth': df_S,
128
+ 'Coverage': df_C,
105
129
  }
106
130
  return sheets_dict
107
131
 
@@ -0,0 +1,105 @@
1
+ from io import BytesIO
2
+
3
+ import numpy as np
4
+ import pandas as pnd
5
+
6
+ from scipy.spatial.distance import pdist
7
+ from scipy.cluster.hierarchy import linkage, cut_tree, dendrogram, leaves_list
8
+
9
+ import matplotlib.pyplot as plt
10
+ from matplotlib.patches import Patch
11
+
12
+
13
+
14
+ def figure_df_C_F1(df_coverage):
15
+
16
+ bin_matrix = df_coverage[[i for i in df_coverage.columns if i not in ['map_ids', 'modeled']]]
17
+ strains = bin_matrix.columns
18
+ bin_matrix = bin_matrix.T # features in column
19
+
20
+ # pdist() / linkage() will loose the accession information. So here we save a dict:
21
+ index_to_strain = {i: strain for i, strain in enumerate(bin_matrix.index)}
22
+
23
+ # Calculate the linkage matrix using Ward clustering and Jaccard dissimilarity
24
+ distances = pdist(bin_matrix, 'jaccard')
25
+ linkage_matrix = linkage(distances, method='ward')
26
+
27
+
28
+ # PART 0: create the frame
29
+ fig, axs = plt.subplots(
30
+ nrows=2, ncols=2,
31
+ figsize=(15, 10),
32
+ gridspec_kw={ # suplots width proportions.
33
+ 'width_ratios': [0.5, 1.0],
34
+ 'height_ratios': [0.015, 0.985]
35
+ }
36
+ )
37
+
38
+ # PART 1: dendrogram
39
+ dn = dendrogram(
40
+ linkage_matrix, ax=axs[1,0],
41
+ orientation='left',
42
+ color_threshold=0, above_threshold_color='black',
43
+ )
44
+
45
+
46
+ ### PART 2: heatmap
47
+ ord_leaves = leaves_list(linkage_matrix)
48
+ ord_leaves = np.flip(ord_leaves) # because leaves are returned in the inverse sense.
49
+ ord_leaves = [index_to_strain[i] for i in ord_leaves] # convert index as number to index as accession
50
+ bin_matrix = bin_matrix.loc[ord_leaves, :] # reordered dataframe.
51
+ axs[1,1].matshow(
52
+ bin_matrix,
53
+ cmap='viridis',
54
+ aspect='auto', # non-squared pixels to fit the axis
55
+ )
56
+
57
+
58
+ ### PART 3: coverage bar
59
+ axs[0,1].matshow(
60
+ df_coverage[['modeled']].T,
61
+ cmap='cool_r',
62
+ aspect='auto', # non-squared pixels to fit the axis
63
+ )
64
+
65
+
66
+ ### PART 4: legends
67
+ legend_feat = [
68
+ Patch(facecolor=plt.colormaps.get_cmap('viridis')(0.0), edgecolor='black', label='Absent'),
69
+ Patch(facecolor=plt.colormaps.get_cmap('viridis')(1.0), edgecolor='black', label='Probably present'),
70
+ ]
71
+ legend_cov = [
72
+ Patch(facecolor=plt.colormaps.get_cmap('cool_r')(0.0), edgecolor='black', label='Not modeled'),
73
+ Patch(facecolor=plt.colormaps.get_cmap('cool_r')(1.0), edgecolor='black', label='Modeled'),
74
+ ]
75
+ l1 = axs[1,0].legend(handles=legend_cov, title='Universe coverage', loc='upper left')
76
+ l2 = axs[1,0].legend(handles=legend_feat, title='KEGG reaction in strain', loc='lower left')
77
+ axs[1,0].add_artist(l1) # keep both legends visible
78
+
79
+
80
+ ### PART 5: aesthetics
81
+ plt.subplots_adjust(wspace=0, hspace=0) # adjust the space between subplots:
82
+ axs[0,0].axis('off') # remove frame and axis
83
+ axs[1,0].axis('off') # remove frame and axis
84
+
85
+ axs[0,1].yaxis.set_visible(False) # remove ticks, tick labels, axis label
86
+
87
+ axs[1,1].xaxis.set_ticks([]) # remove ticks
88
+ axs[1,1].set_xticklabels([]) # remove tick labels
89
+ axs[1,1].xaxis.set_label_position("bottom")
90
+ axs[1,1].set_xlabel("KEGG reactions")
91
+
92
+ axs[1,1].yaxis.set_ticks([]) # remove ticks
93
+ axs[1,1].set_yticklabels([]) # remove tick labels
94
+ axs[1,1].yaxis.set_label_position("right")
95
+ axs[1,1].set_ylabel(f"{len(strains)} strains", rotation=270, labelpad=13) # labelpad is in points (1 point = 1/72 inch)
96
+
97
+
98
+ ### PART 6: save fig
99
+ buf = BytesIO()
100
+ fig.savefig(buf, dpi=300, bbox_inches='tight') # labelpad is in inches (1 point = 1/72 inch)
101
+ plt.close(fig)
102
+ buf.seek(0) # rewind the buffer to the beginning
103
+
104
+
105
+ return buf
@@ -1,8 +1,20 @@
1
1
  import pandas as pnd
2
2
 
3
3
 
4
+ from .figures import figure_df_C_F1
4
5
 
5
- def write_excel_model(model, filepath, df_E, df_B, df_P, df_S):
6
+
7
+
8
+ def write_excel_model(model, filepath, nofigs, df_E, df_B, df_P, df_S, df_C=None):
9
+
10
+
11
+ # generate figures
12
+ if nofigs == False:
13
+
14
+ if df_C is not None:
15
+ df_C_F1 = figure_df_C_F1(df_C)
16
+
17
+
6
18
 
7
19
  df_M = []
8
20
  df_R = []
@@ -33,6 +45,12 @@ def write_excel_model(model, filepath, df_E, df_B, df_P, df_S):
33
45
  df_S.insert(0, 'mid', '') # new columns as first
34
46
  df_S['mid'] = df_S.index
35
47
  df_S = df_S.reset_index(drop=True)
48
+
49
+ # format df_C: universal reaction coverage
50
+ if df_C is not None:
51
+ df_C.insert(0, 'kr', '') # new columns as first
52
+ df_C['kr'] = df_C.index
53
+ df_C = df_C.reset_index(drop=True)
36
54
 
37
55
 
38
56
  for m in model.metabolites:
@@ -81,7 +99,7 @@ def write_excel_model(model, filepath, df_E, df_B, df_P, df_S):
81
99
  df_R = pnd.DataFrame.from_records(df_R)
82
100
  df_T = pnd.DataFrame.from_records(df_T)
83
101
  df_A = pnd.DataFrame.from_records(df_A)
84
- with pnd.ExcelWriter(filepath) as writer:
102
+ with pnd.ExcelWriter(filepath, engine='xlsxwriter') as writer:
85
103
  df_M.to_excel(writer, sheet_name='Metabolites', index=False)
86
104
  df_R.to_excel(writer, sheet_name='Reactions', index=False)
87
105
  df_T.to_excel(writer, sheet_name='Transporters', index=False)
@@ -90,7 +108,12 @@ def write_excel_model(model, filepath, df_E, df_B, df_P, df_S):
90
108
  if df_B is not None: df_B.to_excel(writer, sheet_name='Biomass', index=False)
91
109
  if df_P is not None and len(df_P)!=0: df_P.to_excel(writer, sheet_name='Biolog®', index=False)
92
110
  if df_S is not None and len(df_S.columns)>2: df_S.to_excel(writer, sheet_name='Biosynth', index=False)
93
-
111
+ if df_C is not None:
112
+ df_C.to_excel(writer, sheet_name='Coverage', index=False)
113
+ if nofigs == False:
114
+ worksheet = writer.sheets['Coverage']
115
+ worksheet.insert_image('A1', 'df_C_F1.png', {'image_data': df_C_F1})
116
+
94
117
 
95
118
  sheets_dict = {
96
119
  'model_id': model.id,
@@ -102,6 +125,7 @@ def write_excel_model(model, filepath, df_E, df_B, df_P, df_S):
102
125
  'Biomass': df_B,
103
126
  'Biolog': df_P,
104
127
  'Biosynth': df_S,
128
+ 'Coverage': df_C,
105
129
  }
106
130
  return sheets_dict
107
131
 
@@ -0,0 +1,105 @@
1
+ from io import BytesIO
2
+
3
+ import numpy as np
4
+ import pandas as pnd
5
+
6
+ from scipy.spatial.distance import pdist
7
+ from scipy.cluster.hierarchy import linkage, cut_tree, dendrogram, leaves_list
8
+
9
+ import matplotlib.pyplot as plt
10
+ from matplotlib.patches import Patch
11
+
12
+
13
+
14
+ def figure_df_C_F1(df_coverage):
15
+
16
+ bin_matrix = df_coverage[[i for i in df_coverage.columns if i not in ['map_ids', 'modeled']]]
17
+ strains = bin_matrix.columns
18
+ bin_matrix = bin_matrix.T # features in column
19
+
20
+ # pdist() / linkage() will loose the accession information. So here we save a dict:
21
+ index_to_strain = {i: strain for i, strain in enumerate(bin_matrix.index)}
22
+
23
+ # Calculate the linkage matrix using Ward clustering and Jaccard dissimilarity
24
+ distances = pdist(bin_matrix, 'jaccard')
25
+ linkage_matrix = linkage(distances, method='ward')
26
+
27
+
28
+ # PART 0: create the frame
29
+ fig, axs = plt.subplots(
30
+ nrows=2, ncols=2,
31
+ figsize=(15, 10),
32
+ gridspec_kw={ # suplots width proportions.
33
+ 'width_ratios': [0.5, 1.0],
34
+ 'height_ratios': [0.015, 0.985]
35
+ }
36
+ )
37
+
38
+ # PART 1: dendrogram
39
+ dn = dendrogram(
40
+ linkage_matrix, ax=axs[1,0],
41
+ orientation='left',
42
+ color_threshold=0, above_threshold_color='black',
43
+ )
44
+
45
+
46
+ ### PART 2: heatmap
47
+ ord_leaves = leaves_list(linkage_matrix)
48
+ ord_leaves = np.flip(ord_leaves) # because leaves are returned in the inverse sense.
49
+ ord_leaves = [index_to_strain[i] for i in ord_leaves] # convert index as number to index as accession
50
+ bin_matrix = bin_matrix.loc[ord_leaves, :] # reordered dataframe.
51
+ axs[1,1].matshow(
52
+ bin_matrix,
53
+ cmap='viridis',
54
+ aspect='auto', # non-squared pixels to fit the axis
55
+ )
56
+
57
+
58
+ ### PART 3: coverage bar
59
+ axs[0,1].matshow(
60
+ df_coverage[['modeled']].T,
61
+ cmap='cool_r',
62
+ aspect='auto', # non-squared pixels to fit the axis
63
+ )
64
+
65
+
66
+ ### PART 4: legends
67
+ legend_feat = [
68
+ Patch(facecolor=plt.colormaps.get_cmap('viridis')(0.0), edgecolor='black', label='Absent'),
69
+ Patch(facecolor=plt.colormaps.get_cmap('viridis')(1.0), edgecolor='black', label='Probably present'),
70
+ ]
71
+ legend_cov = [
72
+ Patch(facecolor=plt.colormaps.get_cmap('cool_r')(0.0), edgecolor='black', label='Not modeled'),
73
+ Patch(facecolor=plt.colormaps.get_cmap('cool_r')(1.0), edgecolor='black', label='Modeled'),
74
+ ]
75
+ l1 = axs[1,0].legend(handles=legend_cov, title='Universe coverage', loc='upper left')
76
+ l2 = axs[1,0].legend(handles=legend_feat, title='KEGG reaction in strain', loc='lower left')
77
+ axs[1,0].add_artist(l1) # keep both legends visible
78
+
79
+
80
+ ### PART 5: aesthetics
81
+ plt.subplots_adjust(wspace=0, hspace=0) # adjust the space between subplots:
82
+ axs[0,0].axis('off') # remove frame and axis
83
+ axs[1,0].axis('off') # remove frame and axis
84
+
85
+ axs[0,1].yaxis.set_visible(False) # remove ticks, tick labels, axis label
86
+
87
+ axs[1,1].xaxis.set_ticks([]) # remove ticks
88
+ axs[1,1].set_xticklabels([]) # remove tick labels
89
+ axs[1,1].xaxis.set_label_position("bottom")
90
+ axs[1,1].set_xlabel("KEGG reactions")
91
+
92
+ axs[1,1].yaxis.set_ticks([]) # remove ticks
93
+ axs[1,1].set_yticklabels([]) # remove tick labels
94
+ axs[1,1].yaxis.set_label_position("right")
95
+ axs[1,1].set_ylabel(f"{len(strains)} strains", rotation=270, labelpad=13) # labelpad is in points (1 point = 1/72 inch)
96
+
97
+
98
+ ### PART 6: save fig
99
+ buf = BytesIO()
100
+ fig.savefig(buf, dpi=300, bbox_inches='tight') # labelpad is in inches (1 point = 1/72 inch)
101
+ plt.close(fig)
102
+ buf.seek(0) # rewind the buffer to the beginning
103
+
104
+
105
+ return buf
@@ -141,7 +141,7 @@ def create_model_incore(params):
141
141
  cobra.io.write_sbml_model(model, f'{args.outdir}/{model.id}.xml') # SBML # groups are saved only to SBML
142
142
  logger.info(f"'{args.outdir}/{model.id}.xml' created!")
143
143
  force_id_on_sbml(f'{args.outdir}/{model.id}.xml', model.id) # force introduction of the 'id=""' field
144
- sheets_dict = write_excel_model(model, f'{args.outdir}/{model.id}.mkmodel.xlsx', None, df_B, df_P, df_S)
144
+ sheets_dict = write_excel_model(model, f'{args.outdir}/{model.id}.mkmodel.xlsx', args.nofigs, None, df_B, df_P, df_S)
145
145
  logger.info(f"'{args.outdir}/{model.id}.mkmodel.xlsx' created!")
146
146
 
147
147
 
@@ -141,7 +141,7 @@ def create_model_incore(params):
141
141
  cobra.io.write_sbml_model(model, f'{args.outdir}/{model.id}.xml') # SBML # groups are saved only to SBML
142
142
  logger.info(f"'{args.outdir}/{model.id}.xml' created!")
143
143
  force_id_on_sbml(f'{args.outdir}/{model.id}.xml', model.id) # force introduction of the 'id=""' field
144
- sheets_dict = write_excel_model(model, f'{args.outdir}/{model.id}.mkmodel.xlsx', None, df_B, df_P, df_S)
144
+ sheets_dict = write_excel_model(model, f'{args.outdir}/{model.id}.mkmodel.xlsx', args.nofigs, None, df_B, df_P, df_S)
145
145
  logger.info(f"'{args.outdir}/{model.id}.mkmodel.xlsx' created!")
146
146
 
147
147