File size: 7,435 Bytes
93c029f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
import numpy as np
import matplotlib.pyplot as plt

from src.cocktails.utilities.ingredients_utilities import ingredient_list, extract_ingredients, ingredients_per_type

color_codes = dict(ancestral='#000000',
                   spirit_forward='#2320D2',
                   duo='#6E20D2',
                   champagne_cocktail='#25FFCA',
                   complex_highball='#068F25',
                   simple_highball='#25FF57',
                   collins='#77FF96',
                   julep='#25B8FF',
                   simple_sour='#FBD756',
                   complex_sour='#DCAD07',
                   simple_sour_with_juice='#FF5033',
                   complex_sour_with_juice='#D42306',
                   # simple_sour_with_egg='#FF9C54',
                   # complex_sour_with_egg='#CF5700',
                   # almost_simple_sor='#FF5033',
                   # almost_sor='#D42306',
                   # almost_sor_with_egg='#D42306',
                   other='#9B9B9B'
                   )

def get_subcategories(data):
    subcategories = np.array(data['subcategory'])
    sub_categories_list = sorted(set(subcategories))
    subcat_count = dict(zip(sub_categories_list, [0] * len(sub_categories_list)))
    for sc in data['subcategory']:
        subcat_count[sc] += 1
    return subcategories, sub_categories_list, subcat_count

def get_ingredient_count(data):
    ingredient_counts = dict(zip(ingredient_list, [0] * len(ingredient_list)))
    for ing_str in data['ingredients_str']:
        ingredients, _ = extract_ingredients(ing_str)
        for ing in ingredients:
            ingredient_counts[ing] += 1
    return ingredient_counts

def compute_eucl_dist(a, b):
    return np.sqrt(np.sum((a - b)**2))

def recipe_contains(ingredients, stuff):
    if stuff in ingredient_list:
        return stuff in ingredients
    elif stuff == 'juice':
        return any(['juice' in ing and 'lemon' not in ing and 'lime' not in ing for ing in ingredients])
    elif stuff == 'bubbles':
        return any([ing in ['soda', 'tonic', 'cola', 'sparkling wine', 'ginger beer'] for ing in ingredients])
    elif stuff == 'acid':
        return any([ing in ['lemon juice', 'lime juice'] for ing in ingredients])
    elif stuff == 'vermouth':
        return any([ing in ingredients_per_type['vermouth'] for ing in ingredients])
    elif stuff == 'plain sweet':
        plain_sweet = ingredients_per_type['sweeteners']
        return any([ing in plain_sweet for ing in ingredients])
    elif stuff == 'sweet':
        sweet = ingredients_per_type['sweeteners'] + ingredients_per_type['liqueur'] + ['sweet vermouth', 'lillet blanc']
        return any([ing in sweet for ing in ingredients])
    elif stuff == 'spirit':
        return any([ing in ingredients_per_type['liquor'] for ing in ingredients])
    else:
        raise ValueError



def radar_factory(num_vars, frame='circle'):
    # from stackoverflow's post? Or matplotlib's blog
    """
    Create a radar chart with `num_vars` axes.

    This function creates a RadarAxes projection and registers it.

    Parameters
    ----------
    num_vars : int
        Number of variables for radar chart.
    frame : {'circle', 'polygon'}
        Shape of frame surrounding axes.

    """
    import numpy as np

    from matplotlib.patches import Circle, RegularPolygon
    from matplotlib.path import Path
    from matplotlib.projections.polar import PolarAxes
    from matplotlib.projections import register_projection
    from matplotlib.spines import Spine
    from matplotlib.transforms import Affine2D
    # calculate evenly-spaced axis angles
    theta = np.linspace(0, 2*np.pi, num_vars, endpoint=False)

    class RadarAxes(PolarAxes):

        name = 'radar'
        # use 1 line segment to connect specified points
        RESOLUTION = 1

        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            # rotate plot such that the first axis is at the top
            self.set_theta_zero_location('N')

        def fill(self, *args, closed=True, **kwargs):
            """Override fill so that line is closed by default"""
            return super().fill(closed=closed, *args, **kwargs)

        def plot(self, *args, **kwargs):
            """Override plot so that line is closed by default"""
            lines = super().plot(*args, **kwargs)
            for line in lines:
                self._close_line(line)

        def _close_line(self, line):
            x, y = line.get_data()
            # FIXME: markers at x[0], y[0] get doubled-up
            if x[0] != x[-1]:
                x = np.append(x, x[0])
                y = np.append(y, y[0])
                line.set_data(x, y)

        def set_varlabels(self, labels):
            self.set_thetagrids(np.degrees(theta), labels)

        def _gen_axes_patch(self):
            # The Axes patch must be centered at (0.5, 0.5) and of radius 0.5
            # in axes coordinates.
            if frame == 'circle':
                return Circle((0.5, 0.5), 0.5)
            elif frame == 'polygon':
                return RegularPolygon((0.5, 0.5), num_vars,
                                      radius=.5, edgecolor="k")
            else:
                raise ValueError("Unknown value for 'frame': %s" % frame)

        def _gen_axes_spines(self):
            if frame == 'circle':
                return super()._gen_axes_spines()
            elif frame == 'polygon':
                # spine_type must be 'left'/'right'/'top'/'bottom'/'circle'.
                spine = Spine(axes=self,
                              spine_type='circle',
                              path=Path.unit_regular_polygon(num_vars))
                # unit_regular_polygon gives a polygon of radius 1 centered at
                # (0, 0) but we want a polygon of radius 0.5 centered at (0.5,
                # 0.5) in axes coordinates.
                spine.set_transform(Affine2D().scale(.5).translate(.5, .5)
                                    + self.transAxes)
                return {'polar': spine}
            else:
                raise ValueError("Unknown value for 'frame': %s" % frame)

    register_projection(RadarAxes)
    return theta

def plot_radar_cocktail(representation, labels_dim, labels_cocktails, save_path=None, to_show=False, to_save=False):
    assert to_show or to_save, 'either show or save'
    assert representation.ndim == 2
    n_data, dim_rep = representation.shape
    assert len(labels_cocktails) == n_data
    assert len(labels_dim) == dim_rep
    assert n_data <= 5, 'max 5 representation_analysis please'

    theta = radar_factory(dim_rep, frame='circle')


    fig, ax = plt.subplots(figsize=(9, 9), subplot_kw=dict(projection='radar'))
    fig.subplots_adjust(wspace=0.25, hspace=0.20, top=0.85, bottom=0.05)

    colors = ['b', 'r', 'g', 'm', 'y']
    # Plot the four cases from the example data on separate axes
    ax.set_rgrids([0.2, 0.4, 0.6, 0.8])
    for d, color in zip(representation, colors):
        ax.plot(theta, d, color=color)
    for d, color in zip(representation, colors):
        ax.fill(theta, d, facecolor=color, alpha=0.25)
    ax.set_varlabels(labels_dim)

    # add legend relative to top-left plot
    legend = ax.legend(labels_cocktails, loc=(0.9, .95),
                       labelspacing=0.1, fontsize='small')

    if to_save:
        plt.savefig(save_path, bbox_artists=(legend,), dpi=200)
    else:
        plt.show()