Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add option to highlight certain leaves in custom plots. #131

Merged
merged 2 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ to [Common Changelog](https://common-changelog.org)

### Changed

- Improve error handling for missing input genomes and reference databases. ([#130](https://github.com/metagenlab/zDB/pull/130)) (Niklaus Johner)

### Added

- Improve error handling for missing input genomes and reference databases. ([#130](https://github.com/metagenlab/zDB/pull/130)) (Niklaus Johner)
- Add option to highlight certain leaves in custom plots. ([#131](https://github.com/metagenlab/zDB/pull/131)) (Niklaus Johner)


## 1.3.3 - 2024-08-08

Expand Down
118 changes: 72 additions & 46 deletions webapp/chlamdb/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,55 +674,81 @@ def get_phenotype(self):
return GwasForm


class CustomPlotsForm(forms.Form):

help_text = """Entry IDs can be COG, KO, Pfam, VF, AMR or orthogroups.
IDs should be coma separated.
You can add custom labels by specifying them together with the entry ID
separated by a colon (i.e. entryID:label)."""

entries = forms.CharField(
widget=forms.Textarea(attrs={'cols': 50, 'rows': 5}),
required=True, label="Entry IDs", help_text=help_text)

Entry = namedtuple("Entry", "id label type")

def __init__(self, db, *args, **kwargs):
super().__init__(*args, **kwargs)
self.db = db
self.helper = FormHelper()

self.helper.form_method = 'post'
self.helper.layout = Layout(Fieldset(
"",
Column(
Row(Column(
"entries",
def make_custom_plots_form():

accession_choices = AccessionFieldHandler().get_choices(
with_plasmids=False)

class CustomPlotsForm(forms.Form):

entries_help = """Entry IDs can be COG, KO, Pfam, VF, AMR or orthogroups.
IDs should be coma separated.
You can add custom labels by specifying them together with the entry ID
separated by a colon (i.e. entryID:label)."""

entries = forms.CharField(
widget=forms.Textarea(attrs={'cols': 50, 'rows': 5}),
required=True, label="Entry IDs", help_text=entries_help)

Entry = namedtuple("Entry", "id label type")

highlights_help = "Chose entries that should be highlighted in the tree."
highlights = forms.MultipleChoiceField(
choices=accession_choices,
widget=Select2Multiple(
url="autocomplete_taxid",
forward=(forward.Field("targets", "exclude_taxids_in_groups"),),
attrs={"data-close-on-select": "false",
"data-placeholder": "Nothing selected"}),
required=False, help_text=highlights_help)

def __init__(self, db, *args, **kwargs):
super().__init__(*args, **kwargs)
self.db = db
self.helper = FormHelper()

self.helper.form_method = 'post'
self.helper.layout = Layout(Fieldset(
"",
Column(
Row(Column(
"entries",
css_class='form-group col-lg-12 col-md-12 col-sm-12'),
Column(
"highlights",
css_class='form-group col-lg-12 col-md-12 col-sm-12'),
),
Row(Submit('submit', 'Make plot'),
css_class='form-group col-lg-12 col-md-12 col-sm-12'),
),
Row(Submit('submit', 'Make plot'),
css_class='form-group col-lg-12 col-md-12 col-sm-12'),
css_class="col-lg-8 col-md-8 col-sm-12")
css_class="col-lg-8 col-md-8 col-sm-12")
)
)
)

def clean_entries(self):
raw_entries = self.cleaned_data["entries"].split(",")
parser = EntryIdParser(self.db)
entries = []
for entry in raw_entries:
entry = entry.strip()
if ":" in entry:
entry, label = entry.split(":", 1)
else:
label = entry
try:
object_type, entry_id = parser.id_to_object_type(entry)
except Exception:
raise ValidationError(f'Invalid identifier "{entry}".',
code="invalid")
entries.append(self.Entry(entry_id, label, object_type))
return entries
def clean_entries(self):
raw_entries = self.cleaned_data["entries"].split(",")
parser = EntryIdParser(self.db)
entries = []
for entry in raw_entries:
entry = entry.strip()
if ":" in entry:
entry, label = entry.split(":", 1)
else:
label = entry
try:
object_type, entry_id = parser.id_to_object_type(entry)
except Exception:
raise ValidationError(f'Invalid identifier "{entry}".',
code="invalid")
entries.append(self.Entry(entry_id, label, object_type))
return entries

def get_highlights(self):
indices = self.cleaned_data["highlights"]
taxids, plasmids = AccessionFieldHandler().extract_choices(
indices, False)
return taxids

return CustomPlotsForm


def make_group_add_form(db):
Expand Down
2 changes: 1 addition & 1 deletion webapp/lib/ete_phylo.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def get_leaf_name(self, index):
if idx in self.highlight_leaves:
fgcolor = "red"
label = self.leaves_name.get(idx, self.default_val)
t = TextFace(label, fgcolor=fgcolor, fsize=7, fstyle="italic")
t = TextFace(label, fgcolor=fgcolor, fsize=7)
t.margin_right = 13
return t

Expand Down
13 changes: 8 additions & 5 deletions webapp/views/custom_plots.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from chlamdb.forms import CustomPlotsForm
from chlamdb.forms import make_custom_plots_form
from django.conf import settings
from django.shortcuts import render
from django.views import View
Expand All @@ -19,7 +19,9 @@ class CusomPlotsView(View):
template = 'chlamdb/custom_plots.html'
_db = None

form_class = CustomPlotsForm
def dispatch(self, request, *args, **kwargs):
self.form_class = make_custom_plots_form()
return super(CusomPlotsView, self).dispatch(request, *args, **kwargs)

def get_result_tabs(self, table):
return [
Expand Down Expand Up @@ -60,6 +62,7 @@ def post(self, request, *args, **kwargs):
return render(request, self.template, self.get_context())

entries = self.form.cleaned_data["entries"]
to_highlight = self.form.get_highlights()

# We make 1 query for each entry, although we could of course make
# a single query for each object type, but I don't expect any
Expand All @@ -73,7 +76,7 @@ def post(self, request, *args, **kwargs):
counts.append(hits)

genome_descriptions = self.db.get_genomes_description()
self.prepare_tree(counts, genome_descriptions)
self.prepare_tree(counts, genome_descriptions, to_highlight)
table = self.prepare_table(counts, genome_descriptions)

context = self.get_context(
Expand All @@ -82,7 +85,7 @@ def post(self, request, *args, **kwargs):
)
return render(request, self.template, context)

def prepare_tree(self, counts_list, genome_descriptions):
def prepare_tree(self, counts_list, genome_descriptions, to_highlight):
ref_tree = self.db.get_reference_phylogeny()
ref_names = genome_descriptions.description.to_dict()

Expand All @@ -92,7 +95,7 @@ def prepare_tree(self, counts_list, genome_descriptions):
tree.set_outgroup(R)
tree.ladderize()
e_tree = EteTree(tree)
e_tree.rename_leaves(ref_names)
e_tree.rename_leaves(ref_names, highlight_leaves=to_highlight)
for counts in counts_list:
for label, count in counts.iterrows():
col = SimpleColorColumn.fromSeries(count, header=label, color_gradient=True)
Expand Down