Davide-sd / sympy-plot-backends

An improved plotting module for SymPy
BSD 3-Clause "New" or "Revised" License
42 stars 9 forks source link

Labels keyword not working with boxplot in Matplotlib #29

Closed chubby1968 closed 11 months ago

chubby1968 commented 11 months ago

I expected the following code (using tutorial 6) to produce a boxplot with labels on the x-axis (as in e.g. these examples), but the labels keyword that are set in class BoxplotSeries doesn't seem to work.

I've also tried setting the labels outside the series (inside and outside my boxplot function) but that just seems to produce a second plot (if using the plt member) or not do anything (if using ax member).

Any ideas to get it working?

# type: ignore
from spb import MB
from spb.series import BaseSeries
from spb.backends.matplotlib.renderers.renderer import MatplotlibRenderer

class BoxplotSeries(BaseSeries):
    def __init__(self, data, labels=[], **kwargs):
        super().__init__(**kwargs)

        self.data = data

        if labels != []:
            self.rendering_kw.setdefault("labels", labels)

    def get_data(self):
        return self.data

    def __str__(self):
        return "Boxplot"

def draw(renderer, data):
    p, s = renderer.plot, renderer.series
    handle = p.plt.boxplot(data, **s.rendering_kw)
    p.plt.xticks([1,2],["h","d"])
    return handle

def update(renderer, data, handle):
    raise NotImplementedError

class BoxplotRenderer(MatplotlibRenderer):
    draw_update_map = {draw: update}

MB.renderers_map.update({BoxplotSeries: BoxplotRenderer})

def boxplot(data, labels=[], **kwargs):
    show = kwargs.get("show", True)
    backend = kwargs.get("backend", MB)

    p = backend(BoxplotSeries(data, labels), **kwargs)
    if show:
        p.show()
    return p

if __name__ == "__main__":
    a = boxplot([[1, 2, 3, 10], [1, 2, 3, 8]], labels=["test1", "test2"])
Davide-sd commented 11 months ago

Hello @chubby1968 , thanks for letting me know about it. I've taken a quick look: axis scales are set to linear by default (after a renderer has done its job), which forces numerical axis to be shown instead of categorical axis. I'll try to solve this issue in a few days. I'll keep you posted!

Davide-sd commented 11 months ago

New version is up, it appears to be working as expected:

from spb import MB
from spb.series import BaseSeries
from spb.backends.matplotlib.renderers.renderer import MatplotlibRenderer

class BoxplotSeries(BaseSeries):
    def __init__(self, data, labels=[], **kwargs):
        super().__init__(**kwargs)

        self.data = data

        if labels != []:
            self.rendering_kw.setdefault("labels", labels)

    def get_data(self):
        return self.data

    def __str__(self):
        return "Boxplot"

def draw(renderer, data):
    p, s = renderer.plot, renderer.series
    handle = p.ax.boxplot(data, **s.rendering_kw)
    return handle

def update(renderer, data, handle):
    raise NotImplementedError

class BoxplotRenderer(MatplotlibRenderer):
    draw_update_map = {draw: update}

MB.renderers_map.update({BoxplotSeries: BoxplotRenderer})

def boxplot(data, labels=[], **kwargs):
    show = kwargs.pop("show", True)
    backend = kwargs.get("backend", MB)
    p = backend(BoxplotSeries(data, labels), **kwargs)

    if show:
        p.show()
    return p

a = boxplot([[1, 2, 3, 10], [1, 2, 3, 8]], labels=["test1", "test2"], legend=True)

image

Let me know!

chubby1968 commented 11 months ago

Very nice. I can confirm that it's working as expected.

Thanks for the quick fix!