Giter Club home page Giter Club logo

Comments (8)

NickCH-K avatar NickCH-K commented on June 14, 2024 1

Thank you, good to know!

As for laboriousness, it's mostly just on a pedagogical level rather than a typing-lines level. If there were an so.axhline method, I could do it in the same way I do the rest of the graph. Since there's not, I need to introduce the whole fig thing and .on(fig) as concepts, which are different ways of approaching the graph-making.

from seaborn.

mwaskom avatar mwaskom commented on June 14, 2024 1

The tricky thing as I recall it is that sometimes you would want a horizontal or vertical rules to be dependent on the data, eg you might want to show a distribution and then draw a vertical line at its mean, and then do that when grouping by a color variable, etc.

I do also think that using matplotlib objects directly is an anti-pattern (currently necessary here, but the sign of a feature gap).

from seaborn.

thuiop avatar thuiop commented on June 14, 2024 1

Also, interaction with things like facet may be very weird.

from seaborn.

thuiop avatar thuiop commented on June 14, 2024

I don't think there is anything planned in a near future for this. I have my own code to do this if you like, as thankfully the objects API is modular :

from dataclasses import dataclass
import matplotlib as mpl
from seaborn._marks.base import (
    Mappable,
    MappableColor,
    MappableFloat,
    MappableString,
    Mark,
    resolve_color,
    resolve_properties,
)
from seaborn._stats.base import Stat
from seaborn._core.typing import Default

@dataclass
class StraightLine(Mark):
    """Object drawing an horizontal or vertical line using the axline.
    Giving orient "x" will result in a vertical line.
    """

    color: MappableColor = Mappable("C0")
    alpha: MappableFloat = Mappable(1)
    linewidth: MappableFloat = Mappable(rc="lines.linewidth")
    linestyle: MappableString = Mappable(rc="lines.linestyle")

    def _plot(self, split_gen, scales, orient):

        for keys, data, ax in split_gen():

            vals = resolve_properties(self, keys, scales)
            vals["color"] = resolve_color(self, keys, scales=scales)

            artist_kws = self.artist_kws.copy()
            value = {"x": "y", "y": "x"}[orient]
            xy1_dict = {value: float(data[value].to_numpy()), orient: 0}
            xy2_dict = {value: float(data[value].to_numpy()), orient: 1}
            ax.axline(
                (xy1_dict["x"], xy1_dict["y"]),
                (xy2_dict["x"], xy2_dict["y"]),
                color=vals["color"],
                linewidth=vals["linewidth"],
                linestyle=vals["linestyle"],
                **artist_kws,
            )

    def _legend_artist(self, variables, value, scales):

        keys = {v: value for v in variables}
        vals = resolve_properties(self, keys, scales)
        vals["color"] = resolve_color(self, keys, scales=scales)

        artist_kws = self.artist_kws.copy()

        return mpl.lines.Line2D(
            [],
            [],
            color=vals["color"],
            linewidth=vals["linewidth"],
            linestyle=vals["linestyle"],
            **artist_kws,
        )

I only use this when I want to plot an aggregate value though (e.g. mean or median), otherwise I use the axhline matplotlib API directly which is more convenient (I am not sure why you feel its is more laborious). Also, this uses private attributes which may break in a future update.

from seaborn.

thuiop avatar thuiop commented on June 14, 2024

If there were an so.axhline method, I could do it in the same way I do the rest of the graph.

The question is : what exactly is it supposed to do ? The seaborn objects operate on the DataFrame; there is no reason to have one that plots an arbitrary value, and it is pretty weird semantically. This is why I only use my custom object when plotting aggregate value, which makes sense as seaborn can compute those using Stat objects (avoiding the need for extra computations outside). Also, I personally use .on(fig) or .on(ax) all the time; it would make sense to me to introduce it as you basically need it if you want to interact with your figure in any way afterwards.

from seaborn.

NickCH-K avatar NickCH-K commented on June 14, 2024

That's interesting - given the so.Plot().add() structure, I have thought of the conceptual framing of .add() being that we are operating on the plot itself, rather than the data frame. In that context it would make intuitive sense that you could put things into .add() that are not reliant on the data itself.

from seaborn.

NickCH-K avatar NickCH-K commented on June 14, 2024

Yes, definitely, I think reference lines based on statistics like means (and potentially within groupings) and based on constants that are given meaning by the data but not necessarily calculated based on the data are both very common. In my experience using seaborn.objects it's by far the most common thing I go back to matplotlib to add.

This is just an offhand thought but I wonder if a syntax-compatible way of doing this would be to treat the use of constants like this as a kind of aggregation/Stat. Like if I could do so.Plot().add(so.Line(), so.Agg('constant', 0)). After all, I picked 0 based on its meaning relative to the data, even if the formula I used to do that in my head isn't something it would make sense to write a Python function to calculate - it's easier just to give it the answer.

from seaborn.

mwaskom avatar mwaskom commented on June 14, 2024

To be clear I don't think there are any conceptual problems with so.Rule (which is the terminology I was planning on using) just some annoying things about supporting a mark that typically has a scalar parameterization (e.g. so.Rule(y=0)) but sometimes will have one or more values derived from the data.

from seaborn.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.