<commit_before>import matplotlib.pyplot as plt
import numpy as np

import glue
from glue.client import Client
from glue.util import relim
from glue.exceptions import IncompatibleAttribute

class ScatterLayerManager(object):
    def __init__(self, layer, axes):
        self._layer = layer
        self._axes = axes
        self._visible = True
        self._enabled = True
        self._artist = None
        self._init_artist()

    def _init_artist(self):
        artist = self._axes.scatter([1], [1])
        artist.set_offsets(np.zeros((0, 2)))
        self._artist = artist

    def _remove_artist(self):
        if self._artist in self._axes.collections:
            self._artist.remove()

    def set_enabled(self, state):
        self._enabled = state
        self._artist.set_visible(state and self.is_visible())

    def set_visible(self, state):
        self._visible = state
        self._artist.set_visible(state and self.is_enabled())

    def is_enabled(self):
        return self._enabled

    def is_visible(self):
        return self._visible

    def get_data(self):
        return self._artist.get_offsets()

    def sync_style(self):
        style = self._layer.style
        artist = self._artist
        artist.set_edgecolor('none')
        artist.set_facecolor(style.color)
        try:
            artist.get_sizes().data[0] = style.markersize
        except TypeError:
            artist.get_sizes()[0] = style.markersize

        artist.set_alpha(style.alpha)

    def set_data(self, x, y):
        xy = np.zeros((x.size, 2))
        xy[:, 0] = x
        xy[:, 1] = y
        self._artist.set_offsets(xy)

    def set_zorder(self, order):
        self._artist.set_zorder(order)

    def get_zorder(self):
        return self._artist.get_zorder()

    def __del__(self):
        self._remove_artist()


class ScatterClient(Client):
    """
    A client class that uses matplotlib to visualize tables as scatter plots.
    """
    def __init__(self, data=None, figure=None, axes=None):
        """
        Create a new ScatterClient object

        Inputs:
        =======
        data : `glue.data.DataCollection` instance

        figure : matplotlib Figure instance (optional)
           Which figure instance to draw to. One will be created if
           not provided

        axes : matplotlib Axes instance (optional)
           Which axes instance to use. Will be created if necessary
        """
        Client.__init__(self, data=data)

        self.managers = {}

        self.xatt = None
        self.yatt = None
        self._layer_updated = False # debugging

        if figure is None:
            if axes is not None:
                figure = axes.figure
            else:
                figure = plt.figure()
        if axes is None:
            ax = figure.add_subplot(111)
        else:
            if axes.figure is not figure:
                raise TypeError("Axes and Figure inputs do not "
                                "belong to each other")
            ax = axes
        self.ax = ax

    def is_layer_present(self, layer):
        """ True if layer is plotted """
        return layer in self.managers

    def get_layer_order(self, layer):
        return self.managers[layer].get_zorder()

    def plottable_attributes(self, layer):
        data = layer.data
        return [c for c in data.component_ids() if
                np.can_cast(data[c].dtype, np.float)]

    def add_layer(self, layer):
        """ Adds a new visual layer to a client, to display either a dataset
        or a subset. Updates both the client data structure and the
        plot.

        Inputs:
        =======
        layer : `glue.data.Data` or `glue.subset.Subset` object
            The layer to add
        """
        if layer.data not in self.data:
            raise TypeError("Layer not in data collection")
        if layer in self.managers:
            return
        self.managers[layer] = ScatterLayerManager(layer, self.ax)
        self._bring_subsets_to_front()
        self._update_layer(layer)
        self._ensure_subsets_added(layer)

    def _ensure_subsets_added(self, layer):
        if not isinstance(layer, glue.Data):
            return
        for subset in layer.subsets:
            self.add_layer(subset)

    def _bring_subsets_to_front(self):
        """ Make sure subsets are in front of data """
        nlayers = len(self.managers)
        for i, data in enumerate(self.data):
            if data not in self.managers:
                continue
            self.managers[data].set_zorder(i * nlayers)
            for j, sub in enumerate(data.subsets):
                if sub not in self.managers:
                    continue
                self.managers[sub].set_zorder(i * nlayers + j + 1)

    def _snap_xlim(self):
        """
        Reset the plotted x rng to show all the data
        """
        rng = [np.infty, -np.infty]
        is_log = self.ax.get_xscale() == 'log'
        for layer in self.managers:
            manager = self.managers[layer]
            if not manager.is_visible():
                continue
            xy = manager.get_data()
            if xy.shape[0] == 0:
                continue
            rng0 = relim(min(xy[:, 0]), max(xy[:, 0]), is_log)
            rng[0] = min(rng[0], rng0[0])
            rng[1] = max(rng[1], rng0[1])
        if rng[0] == np.infty:
            return

        if self.ax.xaxis_inverted():
            rng = [rng[1], rng[0]]

        self.ax.set_xlim(rng)

    def _snap_ylim(self):
        """
        Reset the plotted y rng to show all the data
        """
        rng = [np.infty, -np.infty]
        is_log = self.ax.get_yscale() == 'log'
        for layer in self.managers:
            manager = self.managers[layer]
            if not manager.is_visible():
                continue
            xy = manager.get_data()
            if xy.shape[0] == 0:
                continue
            rng0 = relim(min(xy[:, 1]), max(xy[:, 1]), is_log)
            rng[0] = min(rng[0], rng0[0])
            rng[1] = max(rng[1], rng0[1])
        if rng[0] == np.infty:
            return

        if self.ax.xaxis_inverted():
            rng = [rng[1], rng[0]]

        self.ax.set_ylim(rng)

    def set_visible(self, layer, state):
        """ Toggle a layer's visibility

        Inputs:
        =======
        layer : `glue.data.Data` or `glue.subset.Subset` instance
              Which layer to modify
        state : boolean
              True to show. False to hide
        """
        if layer not in self.managers:
            return
        self.managers[layer].set_visible(state)
        self._redraw()

    def is_visible(self, layer):
        if layer not in self.managers:
            return False
        return self.managers[layer].is_visible()

    def set_xydata(self, coord, attribute, snap=True):
        """ Redefine which components get assigned to the x/y axes

        Inputs:
        =======
        coord : 'x' or 'y'
           Which axis to reassign
        attribute : string
           Which attribute of the data to use.
        snap : bool
           If True, will rescale x/y axes to fit the data
        """

        if coord not in ('x', 'y'):
            raise TypeError("coord must be one of x,y")

        #update coordinates of data and subsets
        if coord == 'x':
            self.xatt = attribute
        elif coord == 'y':
            self.yatt = attribute

        #update plots
        map(self._update_layer, (l for l in self.managers))

        if coord == 'x' and snap:
            self._snap_xlim()
        elif coord == 'y' and snap:
            self._snap_ylim()

        self._update_axis_labels()

    def _apply_roi(self, roi):
        # every active data layer is set
        # using specified ROI
        for layer in self.managers:
            if layer.data is not layer:
                continue
            if not self.managers[layer].is_enabled():
                continue
            subset_state = glue.subset.RoiSubsetState(layer)
            subset_state.xatt = self.xatt
            subset_state.yatt = self.yatt
            x, y = roi.to_polygon()
            subset_state.roi = glue.roi.PolygonalROI(x, y)
            subset = layer.edit_subset
            subset.subset_state = subset_state

    def set_xdata(self, attribute, snap=True):
        """
        Redefine which component gets plotted on the x axis

        Parameters
        ----------<commit_msg>remove subset state parent reference (now auto-parented)<commit_after>import matplotlib.pyplot as plt
import numpy as np

import glue
from glue.client import Client
from glue.util import relim
from glue.exceptions import IncompatibleAttribute

class ScatterLayerManager(object):
    def __init__(self, layer, axes):
        self._layer = layer
        self._axes = axes
        self._visible = True
        self._enabled = True
        self._artist = None
        self._init_artist()

    def _init_artist(self):
        artist = self._axes.scatter([1], [1])
        artist.set_offsets(np.zeros((0, 2)))
        self._artist = artist

    def _remove_artist(self):
        if self._artist in self._axes.collections:
            self._artist.remove()

    def set_enabled(self, state):
        self._enabled = state
        self._artist.set_visible(state and self.is_visible())

    def set_visible(self, state):
        self._visible = state
        self._artist.set_visible(state and self.is_enabled())

    def is_enabled(self):
        return self._enabled

    def is_visible(self):
        return self._visible

    def get_data(self):
        return self._artist.get_offsets()

    def sync_style(self):
        style = self._layer.style
        artist = self._artist
        artist.set_edgecolor('none')
        artist.set_facecolor(style.color)
        try:
            artist.get_sizes().data[0] = style.markersize
        except TypeError:
            artist.get_sizes()[0] = style.markersize

        artist.set_alpha(style.alpha)

    def set_data(self, x, y):
        xy = np.zeros((x.size, 2))
        xy[:, 0] = x
        xy[:, 1] = y
        self._artist.set_offsets(xy)

    def set_zorder(self, order):
        self._artist.set_zorder(order)

    def get_zorder(self):
        return self._artist.get_zorder()

    def __del__(self):
        self._remove_artist()


class ScatterClient(Client):
    """
    A client class that uses matplotlib to visualize tables as scatter plots.
    """
    def __init__(self, data=None, figure=None, axes=None):
        """
        Create a new ScatterClient object

        Inputs:
        =======
        data : `glue.data.DataCollection` instance

        figure : matplotlib Figure instance (optional)
           Which figure instance to draw to. One will be created if
           not provided

        axes : matplotlib Axes instance (optional)
           Which axes instance to use. Will be created if necessary
        """
        Client.__init__(self, data=data)

        self.managers = {}

        self.xatt = None
        self.yatt = None
        self._layer_updated = False # debugging

        if figure is None:
            if axes is not None:
                figure = axes.figure
            else:
                figure = plt.figure()
        if axes is None:
            ax = figure.add_subplot(111)
        else:
            if axes.figure is not figure:
                raise TypeError("Axes and Figure inputs do not "
                                "belong to each other")
            ax = axes
        self.ax = ax

    def is_layer_present(self, layer):
        """ True if layer is plotted """
        return layer in self.managers

    def get_layer_order(self, layer):
        return self.managers[layer].get_zorder()

    def plottable_attributes(self, layer):
        data = layer.data
        return [c for c in data.component_ids() if
                np.can_cast(data[c].dtype, np.float)]

    def add_layer(self, layer):
        """ Adds a new visual layer to a client, to display either a dataset
        or a subset. Updates both the client data structure and the
        plot.

        Inputs:
        =======
        layer : `glue.data.Data` or `glue.subset.Subset` object
            The layer to add
        """
        if layer.data not in self.data:
            raise TypeError("Layer not in data collection")
        if layer in self.managers:
            return
        self.managers[layer] = ScatterLayerManager(layer, self.ax)
        self._bring_subsets_to_front()
        self._update_layer(layer)
        self._ensure_subsets_added(layer)

    def _ensure_subsets_added(self, layer):
        if not isinstance(layer, glue.Data):
            return
        for subset in layer.subsets:
            self.add_layer(subset)

    def _bring_subsets_to_front(self):
        """ Make sure subsets are in front of data """
        nlayers = len(self.managers)
        for i, data in enumerate(self.data):
            if data not in self.managers:
                continue
            self.managers[data].set_zorder(i * nlayers)
            for j, sub in enumerate(data.subsets):
                if sub not in self.managers:
                    continue
                self.managers[sub].set_zorder(i * nlayers + j + 1)

    def _snap_xlim(self):
        """
        Reset the plotted x rng to show all the data
        """
        rng = [np.infty, -np.infty]
        is_log = self.ax.get_xscale() == 'log'
        for layer in self.managers:
            manager = self.managers[layer]
            if not manager.is_visible():
                continue
            xy = manager.get_data()
            if xy.shape[0] == 0:
                continue
            rng0 = relim(min(xy[:, 0]), max(xy[:, 0]), is_log)
            rng[0] = min(rng[0], rng0[0])
            rng[1] = max(rng[1], rng0[1])
        if rng[0] == np.infty:
            return

        if self.ax.xaxis_inverted():
            rng = [rng[1], rng[0]]

        self.ax.set_xlim(rng)

    def _snap_ylim(self):
        """
        Reset the plotted y rng to show all the data
        """
        rng = [np.infty, -np.infty]
        is_log = self.ax.get_yscale() == 'log'
        for layer in self.managers:
            manager = self.managers[layer]
            if not manager.is_visible():
                continue
            xy = manager.get_data()
            if xy.shape[0] == 0:
                continue
            rng0 = relim(min(xy[:, 1]), max(xy[:, 1]), is_log)
            rng[0] = min(rng[0], rng0[0])
            rng[1] = max(rng[1], rng0[1])
        if rng[0] == np.infty:
            return

        if self.ax.xaxis_inverted():
            rng = [rng[1], rng[0]]

        self.ax.set_ylim(rng)

    def set_visible(self, layer, state):
        """ Toggle a layer's visibility

        Inputs:
        =======
        layer : `glue.data.Data` or `glue.subset.Subset` instance
              Which layer to modify
        state : boolean
              True to show. False to hide
        """
        if layer not in self.managers:
            return
        self.managers[layer].set_visible(state)
        self._redraw()

    def is_visible(self, layer):
        if layer not in self.managers:
            return False
        return self.managers[layer].is_visible()

    def set_xydata(self, coord, attribute, snap=True):
        """ Redefine which components get assigned to the x/y axes

        Inputs:
        =======
        coord : 'x' or 'y'
           Which axis to reassign
        attribute : string
           Which attribute of the data to use.
        snap : bool
           If True, will rescale x/y axes to fit the data
        """

        if coord not in ('x', 'y'):
            raise TypeError("coord must be one of x,y")

        #update coordinates of data and subsets
        if coord == 'x':
            self.xatt = attribute
        elif coord == 'y':
            self.yatt = attribute

        #update plots
        map(self._update_layer, (l for l in self.managers))

        if coord == 'x' and snap:
            self._snap_xlim()
        elif coord == 'y' and snap:
            self._snap_ylim()

        self._update_axis_labels()

    def _apply_roi(self, roi):
        # every active data layer is set
        # using specified ROI
        for layer in self.managers:
            if layer.data is not layer:
                continue
            if not self.managers[layer].is_enabled():
                continue
            subset_state = glue.subset.RoiSubsetState()
            subset_state.xatt = self.xatt
            subset_state.yatt = self.yatt
            x, y = roi.to_polygon()
            subset_state.roi = glue.roi.PolygonalROI(x, y)
            subset = layer.edit_subset
            subset.subset_state = subset_state

    def set_xdata(self, attribute, snap=True):
        """
        Redefine which component gets plotted on the x axis

        Parameters
        ----------
{'fraction_non_alphanumeric': 0.0998937927779089, 'fraction_numerical': 0.00531036110455511, 'mean_word_length': 1.7478923476005188, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3705215', 'n_tokens_mistral': 5144, 'n_tokens_neox': 4930, 'n_words': 1382}