visuals.py 5.13 KB
Newer Older
1
2
3
4
5
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import matplotlib.pyplot as plt
import matplotlib.ticker as plticker
6
import numpy as np
7
8
9
10


class SequencePlot(object):
    """Key class for visualizations with two axis"""
11
    def __init__(self, view, width=40, height=3):
12
13
        self.width = width
        self.height = height
14
15
16
17
18
19
20
21
        self._x = self.get_xpos(view)  # outsourcen in Frames Class und dann hier löschen

    def get_xpos(self, view):
        """calculate frame numbers for x-ticks"""
        
        # TODO Die Frame No. Range könnte ich auch besser zu einer Methode von Frames machen
        return [nr for nr in range(view._frames.start, view._frames.end,
                                   view._frame_step)]  # um X-Achse Minuten anzeigen zu lassen
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

    def _timelabels(self, val, pos):
        min, sec = divmod(int(val), 60)
        timelabel = "{0}:{1:02d}".format(min, sec)
        return timelabel

    # TODO styling und plotten sind hier noch etwas zusammengemischt
    def ittenstyle(self, ax, view):
        
        plt.style.use('ggplot')
        
        fig_coef = self.width / self.height
        tick_cnt = fig_coef / 0.3605405405
        tick_step = int(view._frames.frm_cnt / tick_cnt)
        
        # loc = plticker.MultipleLocator(base=tick_freq) # this locator puts ticks at regular intervals (0.0005)
        loc = plticker.FixedLocator(range(0, view._frames.end, tick_step))
        fmt = plticker.FuncFormatter(self._timelabels)
        ax.xaxis.set_major_locator(loc)
        ax.xaxis.set_major_formatter(fmt)
        ax.set_xlim(view._frames.start - 20, view._frames.end + 20)

        # Beschriftung der Y-Achse
45
        # TODO funktioniert nicht richtig
46
47
48
49
50
51
52
53
        ax.set_ylim(-1, view._bins + 1)
        loc = plticker.FixedLocator(range(0, view._bins + 1, int(view._bins / 8)))
        ax.yaxis.set_major_locator(loc)
        # TODO mit iter_ticks evtl noch die angegebenen Sekunden auf base 60 setzen

        # obere x-achse mit zeitlich versetzten werten
        axt = ax.twiny()
        axt.set_xlim(ax.get_xlim())
54
        axt.set_ylim(ax.get_ylim())
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
        # loc = plticker.MultipleLocator(base=tick_freq)
        # loc = plticker.LinearLocator(20)
        loc = plticker.FixedLocator(range(int(tick_step / 2), view._frames.end, tick_step))
        fmt = plticker.FuncFormatter(self._timelabels)
        axt.xaxis.set_major_locator(loc)
        axt.xaxis.set_major_formatter(fmt)

        ax.set_axis_bgcolor((1, 1, 1))  # TODO: gradient

        chn_label = view._contrast
        ax.set_ylabel(chn_label, {'fontsize': 8})
        ax.set_xlabel('Time', {'fontsize': 8}, y=0.5)
        ax.yaxis.grid(False)
        axt.yaxis.grid(False)
        ax.tick_params(length=0)
        axt.tick_params(length=0)
        ax.xaxis.grid(c=(0.90, 0.90, 0.90))
        axt.xaxis.grid(c=(0.90, 0.90, 0.90))

        return (ax, axt)

76
77
78
    def saveplt(self, title=False, fname='plot.png'):
        if title:
            self._ax.set_title(title, {'fontsize': 14}, y=1.18)
79

80
81
82
83
        self.fig.set_size_inches(self.width, self.height) 
        self.fig.tight_layout()

        self.fig.savefig(fname, dpi=400)
84

85
86
87

class MultivariatePlot(SequencePlot):
    """Scatterplot that shows n features per frame"""
88
89
    def __init__(self, view):
        super(MultivariatePlot, self).__init__(view)
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
        self.fig = plt.figure()
        self._ax = plt.axes()

    def plot(self, view):
        x = view[:, 0]
        y = view[:, 1]
        value = view[:, 2]
        thickness = list([int((v - view._threshold) / 4000) for v in value])

        self._ax, axt = self.ittenstyle(self._ax, view)

        # Plotten
        axt.scatter(x, y, c=(0, 0, 0), s=thickness, linewidths=0)
        # axt.scatter(x, y, c=y, cmap='Greys_r', s=thickness, linewidths=0) # DOC: vmin/vmax sorgt für die Verteilung der Fraben der Colorm 
        # ax.scatter(x, y, c=y, cmap='hsv', s=thickness, linewidths=0)

        self.fig.tight_layout()
        self.fig.set_size_inches(self.width, self.height) 

        self.fig.savefig("intest.png", dpi=200)

        return self.fig, self._ax
112
113
114
115


class UnivariatePlot(SequencePlot):
    """Lineplot that shows one featur per fram"""
116
117
118
    def __init__(self, view):
        super(UnivariatePlot, self).__init__(view)
        # TODO die können evtl. noch in die super class
119
120
        self.fig = plt.figure()
        self._ax = plt.axes()
121
        self._ax, self._axt = self.ittenstyle(self._ax, view)
122

123
    def plot(self, view, mark_gt=False, mark_lt=False):
124

125
126
        # Interpolation mit savitzky_golay funktioniert nicht
        # contrast_points = savitzky_golay(np.array(contrast_points), 51, 7)
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
        self._axt.plot(self._x, view, label=view.feature) 

        # TODO Überführbar in Superclass?
        # evtl. auch eher feature drer View Klasse
        # TODO self._x sollte eine array sein
        npx = np.array(self._x)
        if mark_gt:
            poss = npx[view > mark_gt]
            for pos in poss:
                self._ax.axvline(pos, color='#f3f315', alpha=0.3, linewidth=3)
        elif mark_lt:
            poss = npx[view > mark_gt]
            for pos in poss:
                self._ax.axvline(pos, color='#f3f315', alpha=0.3, linewidth=3)

142
        self._axt.legend()
143

144
        return self.fig