2

I'm using the seaborn.objects interface to label plot points. However, I can't add a trendline if the labels are present.

Adding the argument text='label' and the method .add(so.Line(color='orange'), so.PolyFit()) to so.Plot() in the first example does not render both labels and trendline together.

  1. Is there any way of having both present on the one plot?

  2. Furthermore, how could I plot an x=y line on either of these plots?

Plot with labelled plot points (working):

import seaborn.objects as so
from matplotlib import pyplot as plt
import pandas as pd
import numpy as np

np.random.seed(42)
num_points = 10
df = pd.DataFrame({'x': np.random.randint(1, 100, size=num_points),
                   'y': np.random.randint(1, 100, size=num_points),
                   'label' : [chr(i + 65) for i in range(num_points)]})

fig, ax = plt.subplots()
p = so.Plot(data=df,
            x='x',
            y='y',
            text='label'
            ).add(so.Dot(marker='o')).add(so.Text(halign='left'))
p.on(ax).show()

enter image description here

Plot with trendline (working):

fig, ax = plt.subplots()
p = so.Plot(data=df,
            x='x',
            y='y',
            ).add(so.Dot(marker='o')).add(so.Line(color='orange'), so.PolyFit())
p.on(ax).show()

enter image description here

However, a plot with code for both labelled plot points and trendline only displays the former:

fig, ax = plt.subplots()
p = so.Plot(data=df,
            x='x',
            y='y',
            text='label',
            ).add(so.Dot(marker='o')).add(so.Text(halign='left')).add(so.Line(color='orange'), so.PolyFit())
p.on(ax).show()

enter image description here

doine
  • 336
  • 1
  • 12
  • Not sure I'm following what the question is here — your plot with the trendline does not add a Text mark? – mwaskom Jul 08 '23 at 19:52
  • 2
    @mwaskom The op wants a trendline, and text labels for the scatter markers, but `.add(so.Dot(marker='o')).add(so.Text(halign='left')).add(so.Line(color='orange'), so.PolyFit())` doesn't add the trendline. – Trenton McKinney Jul 08 '23 at 20:31

1 Answers1

2

In the example you provided, text='label' was set in so.Plot which results in the text labels being mapped to all layers. For some reason this global mapping then gets overridden in the Line/PolyFit layer. I found that if you instead set the text='label' mapping in the so.Text() layer, then it prevents it from being removed by other layers. In other words, just a small change to your code where you move text='label' further down:

fig, ax = plt.subplots()
p = (
    so.Plot(data=df, x='x', y='y')
    .add(so.Dot(marker='o'))
    .add(so.Text(halign='left'), text='label') #set the text mapping here
    .add(so.Line(color='orange'), so.PolyFit())
)
p.on(ax).show()

Screenshot of result

Regarding your second question about adding an identity line to the plot, I am not sure if there's a way using so, but since you're using matplotib, here's how I would do it:

fig, ax = plt.subplots()
p = (
    so.Plot(data=df, x='x', y='y')
    .add(so.Dot(marker='o'))
    .add(so.Text(halign='left'), text='label')
    .add(so.Line(color='orange'), so.PolyFit())
    .on(ax)
)
p_axes = p.plot()._figure.gca() #get the matplotlib handle of the p object
p_axes.plot(p_axes.get_xlim(), p_axes.get_xlim()) #plot identity line

enter image description here

doine
  • 336
  • 1
  • 12
some3128
  • 1,430
  • 1
  • 2
  • 8
  • 1
    Fantastic! Is an identity line different from plotting `x=y`? If so, what I really wanted to try and do was plot an `x=y` line. The identity line doesn't appear to follow this. How would you handle that given the `so` code? – doine Jul 29 '23 at 10:24
  • 1
    Yes you're right. I haven't plotted an identity line above. I've incorrectly plotted some other line. Identity line should be y=x. I've amended the code (but not the figure). – some3128 Jul 29 '23 at 11:47
  • 1
    Thanks. Really appreciate this. I generated the correct image. I can edit it later once pending edits decrease – doine Jul 29 '23 at 12:08