Skip to content

Commit ebbb190

Browse files
committed
PCA: Add lines and labels showing the explained variance
1 parent ae82d28 commit ebbb190

File tree

1 file changed

+32
-8
lines changed

1 file changed

+32
-8
lines changed

Orange/widgets/unsupervised/owpca.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ def __init__(self):
125125
axis.setLabel("Principal Components")
126126
axis = self.plot.getAxis("left")
127127
axis.setLabel("Proportion of variance")
128+
self.plot_horlabels = []
129+
self.plot_horlines = []
128130

129131
self.plot.getViewBox().setMenuEnabled(False)
130132
self.plot.getViewBox().setMouseEnabled(False, False)
@@ -199,6 +201,8 @@ def clear(self):
199201
self._variance_ratio = None
200202
self._cumulative = None
201203
self._line = None
204+
self.plot_horlabels = []
205+
self.plot_horlines = []
202206
self.plot.clear()
203207

204208
def get_model(self):
@@ -231,29 +235,49 @@ def _setup_plot(self):
231235
antialias=True,
232236
name="Cumulative Variance")
233237

238+
cutpos = self._nselected_components() - 1
234239
self._line = pg.InfiniteLine(
235-
angle=90, pos=self._nselected_components() - 1, movable=True,
236-
bounds=(0, p - 1)
237-
)
240+
angle=90, pos=cutpos, movable=True, bounds=(0, p - 1))
238241
self._line.setCursor(Qt.SizeHorCursor)
239-
self._line.setPen(pg.mkPen(QColor(Qt.darkGray), width=5))
242+
self._line.setPen(pg.mkPen(QColor(Qt.black), width=2))
240243
self._line.sigPositionChanged.connect(self._on_cut_changed)
241-
242244
self.plot.addItem(self._line)
245+
246+
self.plot_horlines = (
247+
pg.PlotCurveItem(pen=pg.mkPen(QColor(Qt.blue), style=Qt.DashLine)),
248+
pg.PlotCurveItem(pen=pg.mkPen(QColor(Qt.blue), style=Qt.DashLine)))
249+
self.plot_horlabels = (
250+
pg.TextItem(color=QColor(Qt.black), anchor=(1, 0)),
251+
pg.TextItem(color=QColor(Qt.black), anchor=(1, 1)))
252+
for item in self.plot_horlabels + self.plot_horlines:
253+
self.plot.addItem(item)
254+
self._set_horline_pos()
255+
243256
self.plot.setRange(xRange=(0.0, p - 1), yRange=(0.0, 1.0))
244257
self._update_axis()
245258

259+
def _set_horline_pos(self):
260+
cutidx = self.ncomponents - 1
261+
for line, label, curve in zip(self.plot_horlines, self.plot_horlabels,
262+
(self._variance_ratio, self._cumulative)):
263+
y = curve[cutidx]
264+
line.setData([-1, cutidx], 2 * [y])
265+
label.setPos(cutidx, y)
266+
label.setPlainText("{:.2f}".format(y))
267+
246268
def _on_cut_changed(self, line):
247269
# cut changed by means of a cut line over the scree plot.
248-
value = line.value()
249-
self._line.setValue(round(value))
270+
value = int(round(line.value()))
271+
self._line.setValue(value)
250272
current = self._nselected_components()
251-
components = int(numpy.floor(value)) + 1
273+
components = value + 1
252274

253275
if not (self.ncomponents == 0 and
254276
components == len(self._variance_ratio)):
255277
self.ncomponents = components
256278

279+
self._set_horline_pos()
280+
257281
if self._pca is not None:
258282
self.variance_covered = self._cumulative[components - 1] * 100
259283

0 commit comments

Comments
 (0)