<commit_before>import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.dates import DateFormatter
from matplotlib.ticker import MultipleLocator

from .components import colors, shapes, linestyles, aes
from .components.legend import draw_legend
from .geoms import *
from .scales import *
from .themes import *
from .utils import *

import sys
import re


def is_identity(x):
    if x in colors.COLORS:
        return True
    elif x in shapes.SHAPES:
        return True
    elif isinstance(x, (float, int)):
        return True
    else:
        return False


theme_gray()

class ggplot(object):
    """
    ggplot is the base layer or object that you use to define
    the components of your chart (x and y axis, shapes, colors, etc.).
    You can combine it with layers (or geoms) to make complex graphics
    with minimal effort.

    Parameters
    -----------
    aesthetics:  aes (ggplot.components.aes.aes)
        aesthetics of your plot
    data:  pandas DataFrame (pd.DataFrame)
        a DataFrame with the data you want to plot

    Examples
    ----------
    p = ggplot(aes(x='x', y='y'), data=diamonds)
    print p + geom_point()
    """

    CONTINUOUS = ['x', 'y', 'size', 'alpha']
    DISCRETE = ['color', 'shape', 'marker', 'alpha', 'linestyle']

    def __init__(self, aesthetics, data):
        # ggplot should just 'figure out' which is which
        if not isinstance(data, pd.DataFrame):
            aesthetics, data = data, aesthetics

        self.aesthetics = aesthetics
        self.data = data

        # TODO: This should probably be modularized
        # Look for alias/lambda functions
        for ae, name in self.aesthetics.items():
            if name not in self.data and not is_identity(name):
                result = re.findall(r'(?:[A-Z])|(?:[A-Za_-z0-9]+)|(?:[/*+_=\(\)-])', name)
                if re.match("factor[(][A-Za-z_0-9]+[)]", name):
                    m = re.search("factor[(]([A-Za-z_0-9]+)[)]", name)
                    self.data[name] = self.data[m.group(1)].apply(str)
                else:
                    lambda_column = ""
                    for item in result:
                        if re.match("[/*+_=\(\)-]", item):
                            pass
                        elif re.match("^[0-9.]+$", item):
                            pass
                        else:
                            item = "self.data.get('%s')" % item
                        lambda_column += item
                    self.data[name] = eval(lambda_column)
        # defaults
        self.geoms= []
        self.n_wide = 1
        self.n_high = 1
        self.n_dim_x = None
        self.n_dim_y = None
        # facets
        self.facets = []
        self.facet_type = None
        self.facet_scales = None
        # components
        self.title = None
        self.xlab = None
        self.ylab = None
        # format for x/y major ticks
        self.xtick_formatter = None
        self.xbreaks = None
        self.xtick_labels = None
        self.xmajor_locator = None
        self.xminor_locator = None
        self.ytick_formatter = None
        self.xlimits = None
        self.ylimits = None
        self.scale_y_reverse = None
        self.scale_x_reverse = None
        # legend is a dictionary of { legend_type: { visual_value: legend_key } },
        # where legend_type is one of "color", "linestyle", "marker", "size";
        # visual_value is color value, line style, marker character, or size value;
        # and legend_key is usually a quantile (???).
        self.legend = {}

        # continuous color configs
        self.color_scale = None
        self.colormap = plt.cm.Blues

    def __repr__(self):
        # TODO: Currently plotting the wrong number of facets.
        if self.facet_type=="grid":
            fig, axs = plt.subplots(self.n_high, self.n_wide,
                    sharex=True, sharey=True)
            plt.subplots_adjust(wspace=.05, hspace=.05)
        elif self.facet_type=="wrap":
            subplots_available = self.n_wide * self.n_high
            extra_subplots = subplots_available - self.n_dim_x

            fig, axs = plt.subplots(self.n_high, self.n_wide)
            for extra_plot in axs.flatten()[-extra_subplots:]:
                extra_plot.axis('off')

            # TODO: This isn't working
            plots = [None for i in range(self.n_dim_x)]
            for i in range(self.n_dim_x):
                idx = (i % self.n_high) * self.n_wide + (i % self.n_wide)
                plots[idx] = (i % self.n_wide, i % self.n_high)

            plots = [plot for plot in plots if plot is not None]
            plots = sorted(plots, key=lambda x: x[1] + x[0] * self.n_high + 1)

        else:
            fig, axs = plt.subplots(self.n_high, self.n_wide)

        plt.subplot(self.n_wide, self.n_high, 1)

        # Faceting just means doing an additional groupby. The
        # dimensions of the plot remain the same
        if self.facets:
            cntr = 0
            if len(self.facets)==2:
                for facets, frame in self.data.groupby(self.facets):
                    pos = self.facet_pairs.index(facets) + 1
                    plt.subplot(self.n_wide, self.n_high, pos)
                    for layer in self._get_layers(frame):
                        for geom in self.geoms:
                            callbacks = geom.plot_layer(layer)
                # This needs to enumerate all possibilities
                for pos, facets in enumerate(self.facet_pairs):
                    pos += 1
                    if pos <= self.n_high:
                        plt.subplot(self.n_wide, self.n_high, pos)
                        plt.table(cellText=[[facets[1]]], loc='top',
                                cellLoc='center', cellColours=[['lightgrey']])
                    if (pos % self.n_high)==0:
                        plt.subplot(self.n_wide, self.n_high, pos)
                        x = max(plt.xticks()[0])
                        y = max(plt.yticks()[0])
                        ax = axs[pos % self.n_high][pos % self.n_wide]
                        plt.text(x*1.025, y/2., facets[0],
                            bbox=dict(facecolor='lightgrey', color='black'),
                            fontdict=dict(rotation=-90, verticalalignment="center")
                        )
                    plt.subplot(self.n_wide, self.n_high, pos)

                # Handle the different scale types here (free|free_y|free_x|None) and 
                # also make sure that only the left column gets y scales and the bottom
                # row gets x scales
                scale_facet(self.n_wide, self.n_high, self.facet_pairs, self.facet_scales)<commit_msg>vertical alignment for labels on facet_grid<commit_after>import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.dates import DateFormatter
from matplotlib.ticker import MultipleLocator

from .components import colors, shapes, linestyles, aes
from .components.legend import draw_legend
from .geoms import *
from .scales import *
from .themes import *
from .utils import *

import sys
import re


def is_identity(x):
    if x in colors.COLORS:
        return True
    elif x in shapes.SHAPES:
        return True
    elif isinstance(x, (float, int)):
        return True
    else:
        return False


theme_gray()

class ggplot(object):
    """
    ggplot is the base layer or object that you use to define
    the components of your chart (x and y axis, shapes, colors, etc.).
    You can combine it with layers (or geoms) to make complex graphics
    with minimal effort.

    Parameters
    -----------
    aesthetics:  aes (ggplot.components.aes.aes)
        aesthetics of your plot
    data:  pandas DataFrame (pd.DataFrame)
        a DataFrame with the data you want to plot

    Examples
    ----------
    p = ggplot(aes(x='x', y='y'), data=diamonds)
    print p + geom_point()
    """

    CONTINUOUS = ['x', 'y', 'size', 'alpha']
    DISCRETE = ['color', 'shape', 'marker', 'alpha', 'linestyle']

    def __init__(self, aesthetics, data):
        # ggplot should just 'figure out' which is which
        if not isinstance(data, pd.DataFrame):
            aesthetics, data = data, aesthetics

        self.aesthetics = aesthetics
        self.data = data

        # TODO: This should probably be modularized
        # Look for alias/lambda functions
        for ae, name in self.aesthetics.items():
            if name not in self.data and not is_identity(name):
                result = re.findall(r'(?:[A-Z])|(?:[A-Za_-z0-9]+)|(?:[/*+_=\(\)-])', name)
                if re.match("factor[(][A-Za-z_0-9]+[)]", name):
                    m = re.search("factor[(]([A-Za-z_0-9]+)[)]", name)
                    self.data[name] = self.data[m.group(1)].apply(str)
                else:
                    lambda_column = ""
                    for item in result:
                        if re.match("[/*+_=\(\)-]", item):
                            pass
                        elif re.match("^[0-9.]+$", item):
                            pass
                        else:
                            item = "self.data.get('%s')" % item
                        lambda_column += item
                    self.data[name] = eval(lambda_column)
        # defaults
        self.geoms= []
        self.n_wide = 1
        self.n_high = 1
        self.n_dim_x = None
        self.n_dim_y = None
        # facets
        self.facets = []
        self.facet_type = None
        self.facet_scales = None
        # components
        self.title = None
        self.xlab = None
        self.ylab = None
        # format for x/y major ticks
        self.xtick_formatter = None
        self.xbreaks = None
        self.xtick_labels = None
        self.xmajor_locator = None
        self.xminor_locator = None
        self.ytick_formatter = None
        self.xlimits = None
        self.ylimits = None
        self.scale_y_reverse = None
        self.scale_x_reverse = None
        # legend is a dictionary of { legend_type: { visual_value: legend_key } },
        # where legend_type is one of "color", "linestyle", "marker", "size";
        # visual_value is color value, line style, marker character, or size value;
        # and legend_key is usually a quantile (???).
        self.legend = {}

        # continuous color configs
        self.color_scale = None
        self.colormap = plt.cm.Blues

    def __repr__(self):
        # TODO: Currently plotting the wrong number of facets.
        if self.facet_type=="grid":
            fig, axs = plt.subplots(self.n_high, self.n_wide,
                    sharex=True, sharey=True)
            plt.subplots_adjust(wspace=.05, hspace=.05)
        elif self.facet_type=="wrap":
            subplots_available = self.n_wide * self.n_high
            extra_subplots = subplots_available - self.n_dim_x

            fig, axs = plt.subplots(self.n_high, self.n_wide)
            for extra_plot in axs.flatten()[-extra_subplots:]:
                extra_plot.axis('off')

            # TODO: This isn't working
            plots = [None for i in range(self.n_dim_x)]
            for i in range(self.n_dim_x):
                idx = (i % self.n_high) * self.n_wide + (i % self.n_wide)
                plots[idx] = (i % self.n_wide, i % self.n_high)

            plots = [plot for plot in plots if plot is not None]
            plots = sorted(plots, key=lambda x: x[1] + x[0] * self.n_high + 1)

        else:
            fig, axs = plt.subplots(self.n_high, self.n_wide)

        plt.subplot(self.n_wide, self.n_high, 1)

        # Faceting just means doing an additional groupby. The
        # dimensions of the plot remain the same
        if self.facets:
            cntr = 0
            if len(self.facets)==2:
                # store the extreme x and y coordinates of each pair of axes			
                axis_extremes = np.zeros(shape=(self.n_high * self.n_wide, 4))
                xlab_offset = .15
                for iter, (facets, frame) in enumerate(self.data.groupby(self.facets)):
                    pos = self.facet_pairs.index(facets) + 1
                    plt.subplot(self.n_wide, self.n_high, pos)
                    for layer in self._get_layers(frame):
                        for geom in self.geoms:
                            callbacks = geom.plot_layer(layer)
                    axis_extremes[iter] = [min(plt.xlim()), max(plt.xlim()), 
                        min(plt.ylim()), max(plt.ylim())]
                # find the grid wide data extremeties
                xlab_min, ylab_min = np.min(axis_extremes, axis=0)[[0,2]] 
                xlab_max, ylab_max = np.max(axis_extremes, axis=0)[[1,3]]
                # position of vertical labels for facet grid 
                xlab_pos = xlab_max + xlab_offset
                ylab_pos = ylab_max - float(ylab_max-ylab_min)/2
                # This needs to enumerate all possibilities
                for pos, facets in enumerate(self.facet_pairs):
                    pos += 1
                    if pos <= self.n_high:
                        plt.subplot(self.n_wide, self.n_high, pos)
                        plt.table(cellText=[[facets[1]]], loc='top',
                                cellLoc='center', cellColours=[['lightgrey']])
                    if (pos % self.n_high)==0:
                        plt.subplot(self.n_wide, self.n_high, pos)
                        x = max(plt.xticks()[0])
                        y = max(plt.yticks()[0])
                        ax = axs[pos % self.n_high][pos % self.n_wide]
                        plt.text(xlab_pos, ylab_pos, facets[0],
                            bbox=dict(facecolor='lightgrey', edgecolor='lightgray', color='black', 
                                width=mpl.rcParams['font.size']*1.65),
                            fontdict=dict(rotation=-90, verticalalignment="center", horizontalalignment='left')
                        )
                    plt.subplot(self.n_wide, self.n_high, pos)

                # Handle the different scale types here (free|free_y|free_x|None) and 
                # also make sure that only the left column gets y scales and the bottom
                # row gets x scales
                scale_facet(self.n_wide, self.n_high, self.facet_pairs, self.facet_scales)
{'fraction_non_alphanumeric': 0.10828291258084707, 'fraction_numerical': 0.005424577508867098, 'mean_word_length': 1.667408644036357, 'pattern_counts': {'":': 4, '<': 5, '<?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': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6295650', 'n_tokens_mistral': 4472, 'n_tokens_neox': 4175, 'n_words': 1126}