-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvisualization.py
154 lines (120 loc) · 5.11 KB
/
visualization.py
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
"""
Code in this file is adapting parts of original skfuzzy/control/visualization
from scikit-fuzzy 0.4.2, in hopes to improve performance and visuals.
"""
import time
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.axes import Axes
from matplotlib.figure import Figure
from skfuzzy.fuzzymath.fuzzy_ops import interp_membership
from skfuzzy.control.fuzzyvariable import FuzzyVariable, Term
from skfuzzy.control.controlsystem import CrispValueCalculator, ControlSystem, ControlSystemSimulation
class MyFuzzyVariableVisualizer(object):
def __init__(self, fuzzy_var, ax=None, fig=None):
"""
Initialize the fuzzy variable plot.
Parameters
----------
fuzzy_var : FuzzyVariable or Term to plot
"""
# self.term allows us to know if this is a Term quickly, later
self.term = None
if isinstance(fuzzy_var, Term):
self.term = fuzzy_var.label
self.fuzzy_var = fuzzy_var.parent
elif isinstance(fuzzy_var, FuzzyVariable):
self.fuzzy_var = fuzzy_var
else:
raise ValueError("`FuzzyVariableVisualizer` can only be called "
"with a `FuzzyVariable` or a `Term`.")
if ax is not None:
self.fig: Figure = fig
self.ax: Axes = ax
else:
self.fig, self.ax = plt.subplots()
self.plots = {}
def view(self, sim=None, *args, **kwargs):
"""
Visualize this variable and its membership functions with Matplotlib.
The current output membership function will be shown in bold.
Returns
-------
fig : matplotlib Figure
The hosting Figure object.
ax : matplotlib Axis
The Axis upon which the plot is drawn.
Notes
-----
Matplotlib is used, but ``plt.show()`` is not called. Instead, the
Figure and Axis are returned, allowing further user customization if
desired. In a Jupyter notebook, ``.view()`` will be displayed inline.
"""
if sim is None:
# Create an empty simulation so we can view with default values
sim = ControlSystemSimulation(ControlSystem())
self._init_plot()
crispy = CrispValueCalculator(self.fuzzy_var, sim)
ups_universe, output_mf, cut_mfs = crispy.find_memberships()
# Plot the output membership functions
cut_plots = {}
zeros = np.zeros_like(ups_universe, dtype=np.float64)
for label, mf_plot in self.plots.items():
# Only attempt to plot those with cuts
if label in cut_mfs:
# Harmonize color between mf plots and filled overlays
color = mf_plot[0].get_color()
cut_plots[label] = self.ax.fill_between(
ups_universe, zeros, cut_mfs[label],
facecolor=color, alpha=0.4)
# Plot crisp value if available
if len(cut_mfs) > 0 and not all(output_mf == 0):
crisp_value = None
if hasattr(self.fuzzy_var, 'input'):
crisp_value = self.fuzzy_var.input[sim]
elif hasattr(self.fuzzy_var, 'output'):
crisp_value = self.fuzzy_var.output[sim]
# Draw the crisp value at the actual cut height
if crisp_value is not None:
y = 0.
for key, term in self.fuzzy_var.terms.items():
if key in cut_mfs:
y = max(y, interp_membership(self.fuzzy_var.universe,
term.mf, crisp_value))
# Small cut values are hard to see, so simply set them to 1
if y < 0.1:
y = 1.
self.ax.plot([crisp_value] * 2, [0, y],
color='k', lw=3, label='crisp value')
return self.fig, self.ax
def _init_plot(self):
self.ax.clear()
# start = time.time()
# end = time.time()
# print((end - start))
# Formatting: limits
self.ax.set_ylim([0, 1.01])
self.ax.set_xlim([self.fuzzy_var.universe.min(),
self.fuzzy_var.universe.max()])
# Make the plots
for key, term in self.fuzzy_var.terms.items():
# If this is a Term, bold the active mf
lw = 1
if self.term == key:
lw = 3
self.plots[key] = self.ax.plot(self.fuzzy_var.universe,
term.mf,
label=key,
linewidth=lw)
# Place legend in upper left
self.ax.legend(framealpha=0.5)
# Turn off top/right axes
self.ax.spines['top'].set_visible(False)
self.ax.spines['right'].set_visible(False)
self.ax.get_xaxis().tick_bottom()
self.ax.get_yaxis().tick_left()
# Ticks outside the axes
self.ax.tick_params(direction='out')
# Label the axes
self.ax.set_ylabel('Membership')
self.ax.set_xlabel(self.fuzzy_var.label)