mwaskom / seaborn

Statistical data visualization in Python

Home Page:https://seaborn.pydata.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Controlling color of both line and bar at same time using object interface

maddytae opened this issue · comments

Would it not be nice to have ability to have color specified for both event and region? I can pass all color in scale but that would mess up the legend.

(
    so.Plot(fmri,x= "timepoint", y="signal")
      .add(so.Line(color='blue'),so.Agg('mean'),linewidth="event",linestyle='event',)
      .add(so.Bar(), so.Agg(),color='region')
      .scale(color={'parietal':'red','frontal':'green'},
             linewidth={'cue':3,'stim':1},
            linestyle={'cue':'solid','stim':'dashed'})
)
Screenshot 2024-08-07 at 11 08 00 PM

More context

We can change linestyle and linewidth of 'event'. However we can not control color of 'event' at individual event levels because color of individual regions are already controlled at individual region levels. We can control color os all events like blue in above example. We can also pass all elements of event and region to color dict in scale and that would control the color but will mess up the legend.

import pandas as pd
import seaborn as sns
from plotnine import (
    ggplot, aes, geom_line, geom_bar, scale_color_manual,scale_fill_manual,
    scale_linetype_manual, scale_size_manual, theme_minimal
)

# Load the fmri dataset from seaborn
fmri = sns.load_dataset('fmri')

# Aggregate data for line plot
line_data = fmri.groupby(['timepoint', 'event']).signal.mean().reset_index()
bar_data = fmri.groupby(['timepoint', 'region']).signal.mean().reset_index()
# Create the plot
plot = (
    ggplot() +
   
    # Bar plot with aggregation, mapping color to 'region'
    geom_bar(
        aes(x='timepoint', y='signal', fill='region'),
        data=bar_data,
        stat='identity',
        position='stack',

    ) +
     # Line plot with aggregation by 'mean', mapping size, linetype, and color
    geom_line(
        aes(x='timepoint', y='signal', group='event', color='event', linetype='event', size='event'),
        data=line_data
    ) +
    # Custom color, linetype, and size scales
    scale_color_manual(values={'cue': 'blue', 'stim': 'black', 'parietal':'red','frontal':'green'}) +
    scale_fill_manual(values={'cue': 'blue', 'stim': 'black', 'parietal':'red','frontal':'green'}) +
    scale_size_manual(values={'cue': 3, 'stim': 1}) +
    scale_linetype_manual(values={'cue': 'solid', 'stim': 'dashed'}) 
)

plot

Screenshot 2024-08-08 at 9 42 59 PM

I'm also interested in this. Like the OP mentioned the legend looks incorrect when specifying all the colors in scale.

import seaborn as sns
import seaborn.objects as so

fmri = sns.load_dataset('fmri')

(
    so.Plot(fmri, x="timepoint", y="signal")
      .add(so.Line(), so.Agg(), linewidth="event", linestyle='event', color='event')
      .add(so.Bar(), so.Agg(), color='region')
      .scale(color={'parietal':'red', 'frontal':'green',
                    'stim':'black', 'cue':'blue',
                   },
             linewidth={'cue':3, 'stim':1},
             linestyle={'cue':'solid', 'stim':'dashed'})
)

so

Also, in a scenario like this where we wish to specify in scale the mappings of a common visual property (the color in this case) in multiple layers, maybe a nested dictionary like below (currently it does not work) is more readable?

 color={
     'region': {'parietal':'red', 'frontal':'green'},
     'event': {'stim':'black', 'cue':'blue'},
       },

Sorry, this isn’t supported. Maybe one day, but somewhat unlikely.