Marsilea-viz / marsilea

Declarative creation of composable visualization for Python (Complex heatmap, Upset plot, Oncoprint and more~)
https://marsilea.rtfd.io/
MIT License
174 stars 6 forks source link

add Labels legend or customised legend #32

Closed hmassalha closed 6 months ago

hmassalha commented 6 months ago

Thanks for the amazing tool! I have a list of gene labels. I added red color for genes sharing a pathway, and left black the genes that are not part of the pathway. My question is: how I can add a legend for the red labelled text? Something like this:

label_cols = ['r' if l in df2plot[df2plot['pathway']=='RR'].index else 'k' for l in df_heatmap.index ]
gene_names = mp.Labels(df_heatmap.index, fontsize=8, text_props={'color': label_cols})
h.add_right(gene_names)

image

Many thanks, HM

Mr-Milk commented 6 months ago

Thanks for finding marsilea useful. May I ask what's the style of legend that you have in mind for text labels?

hmassalha commented 6 months ago

The idea is to say what is the red color in the labels. I would think about red circle/rectangle with a matching label and title. Thanks.

Mr-Milk commented 6 months ago

Yes, this is possible, we have a custom_legend API, you can do something like below, but this API is a bit buggy and may not be working. If you wait until the next release (0.3.7) next week, this should be working:

import marsilea as ma
import numpy as np
from legenkit import cat_legend

data = np.random.randint(1, 100, (10, 10))

# Your legend
leg = cat_legend(colors=["red", "k"], labels=["red label", "black label"])

h = ma.Heatmap(data)
# Add legend here
h.custom_legend(leg)
h.add_legends()
h.render()

Another alternative is to create add another plot with legend but size 0

import marsilea as ma
import marsilea.plotter as mp
import numpy as np

data = np.random.randint(1, 100, (10, 10))
mock_legend = np.random.choice(["Red Label", "Black Label"], 10)

h = ma.Heatmap(data)
h.add_left(mp.Colors(mock_legend, palette={"Red Label": "r", "Black Label": "k"}), size=0)
h.add_legends()
h.render()

image

hmassalha commented 6 months ago

Thanks for your reply. The second solution worked for me. I had to match the size of mock_legend to the size of data. Using your first code, it didn't work for me. I get RuntimeError: Can not put single artist in more than one figure with two plots. I guess it is missing some extra parameter somewhere...