biotite-dev / biotite

A comprehensive library for computational molecular biology
https://www.biotite-python.org
BSD 3-Clause "New" or "Revised" License
616 stars 99 forks source link

'plot_nucleotide_secondary_structure()' not able to set color for base symbols #333

Closed padix-key closed 3 years ago

padix-key commented 3 years ago

I tried to change the text color of the Text objects representing the bases in plot_nucleotide_secondary_structure(), but I found no appropriate parameter for it. I think this would be a nice option to have.

The source code snippet for the text creation is the following:

https://github.com/biotite-dev/biotite/blob/d308e5fdb0ab59bbe49297a185c35d8180ca3914/src/biotite/structure/graphics/rna.py#L204-L210

@tomtomhdx Could you have a look at it?

t0mdavid-m commented 3 years ago

You should be able to set the text color of the Text objects representing the bases using the base_font parameter. This allows you to set a matplotlib fontdict specifying font related parameters such as text color:

base_font = {'color': 'darkred'}

However, I could not find a proper documentation page in the matplotlib documentation and according to this issue this is a quite unknown feature:

https://github.com/matplotlib/matplotlib/issues/10293

While it might be more user friendly add a base_color parameter to the function, I am worried about bloat as the function already has a lot of parameters. What do you think?

t0mdavid-m commented 3 years ago

While reading the documentation I also noticed that it is only possible to set the fontdict for all bases but not for each individual base. Thus, I think it would be useful to allow an iterable describing the font and color of each individual Text object representing the bases.

padix-key commented 3 years ago

I tried using the base_font parameter to set the color but I got the following Exception:

File "secondary_structure.py", line 53, in <module>
    graphics.plot_nucleotide_secondary_structure(
  File "/home/kunzmann/data/coding/biotite/src/biotite/structure/graphics/rna.py", line 206, in plot_nucleotide_secondary_structure
    t = axes.text(
  File "/home/kunzmann/bin/conda/envs/biotite-dev/lib/python3.8/site-packages/matplotlib/axes/_axes.py", line 644, in text
    t = mtext.Text(x, y, text=s, **effective_kwargs)
  File "/home/kunzmann/bin/conda/envs/biotite-dev/lib/python3.8/site-packages/matplotlib/text.py", line 171, in __init__
    self.update(kwargs)
  File "/home/kunzmann/bin/conda/envs/biotite-dev/lib/python3.8/site-packages/matplotlib/text.py", line 184, in update
    super().update(kwargs)
  File "/home/kunzmann/bin/conda/envs/biotite-dev/lib/python3.8/site-packages/matplotlib/artist.py", line 1064, in update
    ret.append(func(v))
  File "/home/kunzmann/bin/conda/envs/biotite-dev/lib/python3.8/site-packages/matplotlib/cbook/__init__.py", line 1925, in method
    return getattr(self, name)(*args, **kwargs)
  File "/home/kunzmann/bin/conda/envs/biotite-dev/lib/python3.8/site-packages/matplotlib/text.py", line 1251, in set_fontproperties
    self._fontproperties = FontProperties._from_any(fp).copy()
  File "/home/kunzmann/bin/conda/envs/biotite-dev/lib/python3.8/site-packages/matplotlib/font_manager.py", line 695, in _from_any
    return cls(**arg)
TypeError: __init__() got an unexpected keyword argument 'color'

While it might be more user friendly add a base_color parameter to the function, I am worried about bloat as the function already has a lot of parameters. What do you think?

What do you think about replacing base_font parameter with with base_text parameter which is a dict that is given to axes.text():

t = axes.text( 
             x=coords[0], y=coords[1], s=label, 
             ha='center', va='center', **base_text
 ) 

This could include the current font options, but also color and other options and it would not increase the number of parameters for the function.

Thus, I think it would be useful to allow an iterable describing the font and color of each individual Text object representing the bases.

I agree that the user should be able to supply the text properties for each base individually.

t0mdavid-m commented 3 years ago

What do you think about replacing base_font parameter with with base_text parameter which is a dict that is given to axes.text():

This sounds like a good idea.

I will create a PR, allowing the user to set a base_text parameter for all bases or an iterable for each individual base.