Skip to content

Commit ae50e78

Browse files
authored
Merge pull request #1383 from janezd/pca-mark
[ENH] PCA: Add lines and labels showing the explained variance
2 parents e24aa39 + 06a3a7b commit ae50e78

File tree

1 file changed

+33
-11
lines changed

1 file changed

+33
-11
lines changed

Orange/widgets/unsupervised/owpca.py

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from Orange.preprocess import Normalize
1010
from Orange.projection import PCA
1111
from Orange.widgets import widget, gui, settings
12-
from Orange.widgets.io import FileFormat
1312

1413
try:
1514
from orangecontrib import remote
@@ -125,6 +124,8 @@ def __init__(self):
125124
axis.setLabel("Principal Components")
126125
axis = self.plot.getAxis("left")
127126
axis.setLabel("Proportion of variance")
127+
self.plot_horlabels = []
128+
self.plot_horlines = []
128129

129130
self.plot.getViewBox().setMenuEnabled(False)
130131
self.plot.getViewBox().setMouseEnabled(False, False)
@@ -199,6 +200,8 @@ def clear(self):
199200
self._variance_ratio = None
200201
self._cumulative = None
201202
self._line = None
203+
self.plot_horlabels = []
204+
self.plot_horlines = []
202205
self.plot.clear()
203206

204207
def get_model(self):
@@ -231,29 +234,49 @@ def _setup_plot(self):
231234
antialias=True,
232235
name="Cumulative Variance")
233236

237+
cutpos = self._nselected_components() - 1
234238
self._line = pg.InfiniteLine(
235-
angle=90, pos=self._nselected_components() - 1, movable=True,
236-
bounds=(0, p - 1)
237-
)
239+
angle=90, pos=cutpos, movable=True, bounds=(0, p - 1))
238240
self._line.setCursor(Qt.SizeHorCursor)
239-
self._line.setPen(pg.mkPen(QColor(Qt.darkGray), width=5))
241+
self._line.setPen(pg.mkPen(QColor(Qt.black), width=2))
240242
self._line.sigPositionChanged.connect(self._on_cut_changed)
241-
242243
self.plot.addItem(self._line)
244+
245+
self.plot_horlines = (
246+
pg.PlotCurveItem(pen=pg.mkPen(QColor(Qt.blue), style=Qt.DashLine)),
247+
pg.PlotCurveItem(pen=pg.mkPen(QColor(Qt.blue), style=Qt.DashLine)))
248+
self.plot_horlabels = (
249+
pg.TextItem(color=QColor(Qt.black), anchor=(1, 0)),
250+
pg.TextItem(color=QColor(Qt.black), anchor=(1, 1)))
251+
for item in self.plot_horlabels + self.plot_horlines:
252+
self.plot.addItem(item)
253+
self._set_horline_pos()
254+
243255
self.plot.setRange(xRange=(0.0, p - 1), yRange=(0.0, 1.0))
244256
self._update_axis()
245257

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

253274
if not (self.ncomponents == 0 and
254275
components == len(self._variance_ratio)):
255276
self.ncomponents = components
256277

278+
self._set_horline_pos()
279+
257280
if self._pca is not None:
258281
self.variance_covered = self._cumulative[components - 1] * 100
259282

@@ -384,5 +407,4 @@ def main():
384407
return rval
385408

386409
if __name__ == "__main__":
387-
import sys
388-
sys.exit(main())
410+
main()

0 commit comments

Comments
 (0)