From 0ee7bd935e7708e7cd30353cd83dfbf101f7bd10 Mon Sep 17 00:00:00 2001 From: jreus Date: Wed, 21 Nov 2018 12:13:46 +0100 Subject: [PATCH 1/6] updates to ScatterView classes for Qt --- classes/gui/ScatterView.sc | 255 +++++++++++++++++++++++++----------- classes/gui/ScatterView2.sc | 122 ++++++++++++----- 2 files changed, 262 insertions(+), 115 deletions(-) diff --git a/classes/gui/ScatterView.sc b/classes/gui/ScatterView.sc index ac774a1..e284348 100644 --- a/classes/gui/ScatterView.sc +++ b/classes/gui/ScatterView.sc @@ -1,46 +1,86 @@ -// 2005 by till bovermann -// bielefeld university +/********************************************************************* +(C) 2005 Till Bovermann / Bielefeld University +and later... + +(C) 2018 Jonathan Reus / IEM Graz + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + For more details see: https://www.gnu.org/licenses/ +**********************************************************************/ + + +/* +@class ScatterView + +A simple 2-dimensional scatterplot with coordinate axes. + +@usage + +n = 100; +x = Array.series(n, 0.0, 100 / n) + Array.fill(n, {rrand(-10.0, 10.0)}).round(0.01); +y = Array.series(n, 1.0, 100 / n) + Array.fill(n, {rrand(-10.0, 10.0)}).round(0.01); +p = x.collect {|item,i| [item, y[i]] }; // as points + +b = Rect(0,0, 800, 600); +w = Window.new(bounds: b); +j = ScatterView.new(w, b, p, [0,100].asSpec, [0,100].asSpec); +j.drawAxis_(true).symbolColor_(Color.blue).drawMethod_(\fillOval).symbolSize_(5@5); +w.front; + +*/ ScatterView { - var background; var <>highlightColor, highlightSize, <>isHighlight, <>drawAxis, <>drawValues; var <>xAxisName, <>yAxisName; var symbolColor, <>drawMethod = \lineTo; - var adjustedData, specX, specY; + var specX, <>specY; *new {|parent, bounds, data, specX, specY| ^super.new.initPlot( parent, bounds, data, specX, specY ) } - background_ {|color| - background = color; - } + highlightItem_{|item| highlightItem = item.isKindOf(Collection).if({item}, {[item]}); //this.plot.refresh; } + highlightItemRel_{|val| this.highlightItem = (val * (adjustedData.size-1)).asInteger; } + highlightRange{|start, end| this.highlightItem = (start .. end); } + highlightRangeRel{|start, end| var startIndex, endIndex; startIndex = (start * (adjustedData.size-1)).asInteger; endIndex = (end * (adjustedData.size-1)).asInteger; this.highlightItem = (startIndex .. endIndex); } + refresh { plot.refresh; } + data_{|data| adjustedData = data.collect {|item| [specX.unmap(item[0]), specY.unmap(item[1])]; }; highlightItem = min(highlightItem, (adjustedData.size-1)); } + symbolSize_{|point| if(point.isKindOf(Point), {symbolSize = point}, {symbolSize = (point@point)}); } @@ -50,19 +90,18 @@ ScatterView { resize_{arg resize; plot.resize_(resize) } - initPlot { - arg parent, bounds, data, argSpecX, argSpecY; - + initPlot {arg parent, bounds, data, argSpecX, argSpecY; + var widthSpec, heightSpec, cross; var possibleMethods; - + specX = argSpecX ? [0,1].asSpec; specY = argSpecY ? specX.copy; possibleMethods = [\fillRect, \fillOval, \strokeOval, \strokeRect]; - + this.symbolSize = 1; symbolColor = symbolColor ? Color.black; - + background = Color.white; highlightColor = Color.red; highlightItem = 0; @@ -72,28 +111,28 @@ ScatterView { drawValues = false; xAxisName= "X"; yAxisName= "Y"; - + this.data_(data); - + cross = {|rect, width, color| var dx, dy, extX, extY; dx = rect.left; dy = rect.top; extX = rect.width; extY = rect.height; - GUI.pen.use{ - GUI.pen.color = color; - GUI.pen.translate(dx, dy); - GUI.pen.moveTo((0)@(extY*0.5)); - GUI.pen.lineTo(extX@(extY*0.5)); - GUI.pen.moveTo((extX*0.5)@(0)); - GUI.pen.lineTo((extX*0.5)@(extY)); - GUI.pen.stroke; + Pen.use{ + Pen.color = color; + Pen.translate(dx, dy); + Pen.moveTo((0)@(extY*0.5)); + Pen.lineTo(extX@(extY*0.5)); + Pen.moveTo((extX*0.5)@(0)); + Pen.lineTo((extX*0.5)@(extY)); + Pen.stroke; }; }; - - plot = GUI.userView.new(parent, bounds) - .relativeOrigin_(false) + + plot = UserView.new(parent, bounds) + //.relativeOrigin_(false) .drawFunc_({|w| var width, height, rect, pad = 10; if (drawAxis) { pad = 60 }; @@ -101,88 +140,88 @@ ScatterView { width = w.bounds.width - pad; height = w.bounds.height - pad; - GUI.pen.use{ + Pen.use{ // clipping into the boundingbox - GUI.pen.moveTo((w.bounds.left)@(w.bounds.top)); - GUI.pen.lineTo(((w.bounds.left)@(w.bounds.top)) + Pen.moveTo((w.bounds.left)@(w.bounds.top)); + Pen.lineTo(((w.bounds.left)@(w.bounds.top)) + (w.bounds.width@0)); - GUI.pen.lineTo(((w.bounds.left)@(w.bounds.top)) + Pen.lineTo(((w.bounds.left)@(w.bounds.top)) + (w.bounds.width@w.bounds.height)); - GUI.pen.lineTo(((w.bounds.left)@(w.bounds.top)) + Pen.lineTo(((w.bounds.left)@(w.bounds.top)) + (0@w.bounds.height)); - GUI.pen.lineTo((w.bounds.left)@(w.bounds.top)); - GUI.pen.clip; - + Pen.lineTo((w.bounds.left)@(w.bounds.top)); + Pen.clip; + // draw Background - GUI.pen.color = background; - GUI.pen.addRect(w.bounds); - GUI.pen.fill; - + Pen.color = background; + Pen.addRect(w.bounds); + Pen.fill; + // draw data - GUI.pen.color = symbolColor; + Pen.color = symbolColor; if (possibleMethods.includes(drawMethod), { - GUI.pen.beginPath; + Pen.beginPath; adjustedData.do{|item, i| rect = Rect( ( item[0] * width) - (symbolSize.x/2) + (pad/2), - ((1-item[1]) * height) - (symbolSize.y/2) + (pad/2), + ((1-item[1]) * height) - (symbolSize.y/2) + (pad/2), symbolSize.x, symbolSize.y ); - GUI.pen.perform( + Pen.perform( drawMethod, (Rect(w.bounds.left, w.bounds.top, 0, 0) + rect) ); } },{ // else draw lines - GUI.pen.width = symbolSize.x; + Pen.width = symbolSize.x; // move to first position; if (adjustedData.notNil) { - GUI.pen.moveTo( + Pen.moveTo( ((adjustedData[0][0] * width) + (pad/2)) @ (((1-adjustedData[0][1]) * height) + (pad/2)) - + + + (w.bounds.left@w.bounds.top) ); }; // draw lines adjustedData.do{|item, i| - GUI.pen.lineTo( + Pen.lineTo( ((item[0] * width) + (pad/2)) @ - (((1-item[1]) * height) + (pad/2)) - + + (((1-item[1]) * height) + (pad/2)) + + (w.bounds.left@w.bounds.top) ) }; - if(drawMethod == \fill, {GUI.pen.fill},{GUI.pen.stroke}); + if(drawMethod == \fill, {Pen.fill},{Pen.stroke}); }); - + // highlight datapoint if(isHighlight) { highlightItem.do{|item| cross.value((Rect( - (adjustedData[item][0] * width) - - + (adjustedData[item][0] * width) + - (highlightSize.x/2) + (pad/2), - ((1-adjustedData[item][1]) * height) - - - (highlightSize.y/2) - + - (pad/2), - highlightSize.x, highlightSize.y) - + + ((1-adjustedData[item][1]) * height) + - + (highlightSize.y/2) + + + (pad/2), + highlightSize.x, highlightSize.y) + + Rect(w.bounds.left, w.bounds.top, 0, 0)), symbolSize, highlightColor ); }; // od }; - // draw axis + // draw axis if (drawAxis) { - GUI.pen.moveTo((w.bounds.left+(pad/2))@(w.bounds.top+(pad/2))); - GUI.pen.lineTo((w.bounds.left+(pad/2))@(w.bounds.top+w.bounds.height-(pad/2))); - GUI.pen.lineTo( + Pen.moveTo((w.bounds.left+(pad/2))@(w.bounds.top+(pad/2))); + Pen.lineTo((w.bounds.left+(pad/2))@(w.bounds.top+w.bounds.height-(pad/2))); + Pen.lineTo( (w.bounds.left-(pad/2)+w.bounds.width)@(w.bounds.top+w.bounds.height-(pad/2))); specX.minval.round(0.001).asString .drawAtPoint( @@ -199,17 +238,17 @@ ScatterView { - GUI.pen.rotate(-pi/2); - GUI.pen.translate(w.bounds.height.neg, 0); + Pen.rotate(-pi/2); + Pen.translate(w.bounds.height.neg, 0); specY.minval.round(0.001).asString .drawAtPoint((pad/2)@(w.bounds.left+(pad/2) -20)); yAxisName. drawAtPoint((w.bounds.height/2)@(w.bounds.left+(pad/2) -20)); specY.maxval.round(0.001).asString .drawAtPoint((w.bounds.height - (pad/2))@(w.bounds.left+(pad/2) -20)); - GUI.pen.translate(w.bounds.height, 0); - GUI.pen.rotate(pi/2); - GUI.pen.stroke; + Pen.translate(w.bounds.height, 0); + Pen.rotate(pi/2); + Pen.stroke; }; // draw values if (drawValues) { @@ -221,7 +260,7 @@ ScatterView { ) } } - }; // end GUI.pen.use + }; // end Pen.use }); } canFocus_ { arg state = false; @@ -238,12 +277,44 @@ ScatterView { } } +/* +@class ScatterView3d + +A simple 3-dimensional scatterplot with rotation. + + +@usage + +// Generate some toy data with a linear relationship +n = 100; +x = Array.series(n, 0.0, 100 / n) + Array.fill(n, {rrand(-10.0, 10.0)}).round(0.01); +y = Array.series(n, 1.0, 100 / n) + Array.fill(n, {rrand(-10.0, 10.0)}).round(0.01); +z = Array.series(n, 1.0, 100 / n) + Array.fill(n, {rrand(-10.0, 10.0)}).round(0.01); +p = x.collect {|item,i| [item, y[i], z[i]] }; // as points + +// Plot +b = Rect(0,0, 800, 600); +w = Window.new(bounds: b); +j = ScatterView3d.new(w, b, p, [0,100].asSpec, [0,100].asSpec, [0,100].asSpec); +j.symbolColor_(Color.black).drawMethod_(\fillRect).symbolSize_(5@5); +w.front; + +Tdef('animate', { + var i = 0; + inf.do { + j.rot(i, i, 0).refresh; + i = i + 0.03; + 0.05.wait; + }; +}).play(AppClock); + +*/ ScatterView3d { var scatterView; var rotX, rotY, rotZ; var specX, specY, specZ; var data3d; - + *new {|parent, bounds, data, specX, specY, specZ, rotX = 0, rotY = 0, rotZ = 0| ^super.new.init3d(parent, bounds, data, specX, specY, specZ, rotX, rotY, rotZ); } @@ -251,7 +322,7 @@ ScatterView3d { init3d {|parent, bounds, data, argspecX, argspecY, argspecZ, argrotX, argrotY, argrotZ| specX = argspecX ? [0, 1].asSpec; specY = argspecY ? specX.copy; - specZ = argspecY ? specX.copy; + specZ = argspecZ ? specX.copy; rotX = argrotX; rotY = argrotY; @@ -265,11 +336,12 @@ ScatterView3d { this.data = data; this.refresh } + data_{|data| data3d = data.collect {|item| Matrix.withFlatArray(3, 1, [ - specX.unmap(item[0]), - specY.unmap(item[1]), + specX.unmap(item[0]), + specY.unmap(item[1]), specZ.unmap(item[2]) ] * 2 - 1); }; @@ -277,57 +349,79 @@ ScatterView3d { // highlightItem = min(highlightItem, (adjustedData.size-1)); } + refresh { scatterView.refresh; } + rotX_{|val| this.rot(val, rotY, rotZ); } + rotY_{|val| this.rot(rotX, val, rotZ); } + rotZ_{|val| this.rot(rotX, rotY, val); } + + /* + @method + Rotation in radians + */ rot {|rX, rY, rZ| rotX = rX; rotY = rY; rotZ = rZ; scatterView.data = this.pr_project; } + drawMethod_{|method| - scatterView.drawMethod = method; + scatterView.drawMethod = method; } + symbolSize_{|val| - scatterView.symbolSize = val; + scatterView.symbolSize = val; } + symbolColor_{|val| - scatterView.symbolColor = val; + scatterView.symbolColor = val; } + isHighlight_{|val| scatterView.isHighlight_(val); } + highlightItem_{|item| scatterView.highlightItem_(item); } + highlightRange{|start, end| scatterView.highlightRange(start, end); } + highlightColor_{|color| scatterView.highlightColor_(color); } + highlightSize_{|size| scatterView.highlightSize_(size); } + background_{|val| - scatterView.background = val; + scatterView.background = val; } + resize{ ^scatterView.resize } + resize_{arg resize; scatterView.resize_(resize) } + + pr_project { var cx, cy, sx, sy, sz, cz, projectionMatrix; sx = sin(rotX); @@ -337,15 +431,16 @@ ScatterView3d { cx = cos(rotX); cy = cos(rotY); cz = cos(rotZ); - + projectionMatrix = Matrix.with([ [( (cy * cz) - (sx * sy * sz)), (sz.neg * cx), ((cz * sy) + (sz * sx * cy))], [( (cy * sz) + (cz * sx * sy)), ( cz * cx), ((sz * sy) - (sx * cy * cz))] ]); - - + + ^data3d.collect{|row| (projectionMatrix * row).getCol(0) }; } } + diff --git a/classes/gui/ScatterView2.sc b/classes/gui/ScatterView2.sc index 1486832..8109d9b 100644 --- a/classes/gui/ScatterView2.sc +++ b/classes/gui/ScatterView2.sc @@ -1,12 +1,54 @@ -// 2008 by till bovermann -// bielefeld university +/********************************************************************* +(C) 2008 Till Bovermann / Bielefeld University +and later... + +(C) 2018 Jonathan Reus / IEM Graz + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + For more details see: https://www.gnu.org/licenses/ +**********************************************************************/ + + + + + + + +/* +@class ScatterView2 + +A simple scatterplot with mouse select interaction. + +@usage + +n = 20; +x = Array.series(n, 0.0, 100 / n) + Array.fill(n, {rrand(-10.0, 10.0)}).round(0.01); +y = Array.series(n, 1.0, 100 / n) + Array.fill(n, {rrand(-10.0, 10.0)}).round(0.01); +p = x.collect {|item,i| [item, y[i]] }; // as points + +b = Rect(0,0, 800, 600); +w = Window.new(bounds: b); +j = ScatterView2.new(w, b, p, [0,100].asSpec, [0,100].asSpec).itemSize_(5); +w.front; + +*/ ScatterView2 { var background; var <>colorFunc; - var <>itemSize = 2, <>drawMethod = \lineTo; + var <>itemSize = 2; + // TODO: + //var <>drawMethod = \lineTo; //var <>highlightColor, highlightSize, <>isHighlight, <>drawAxis, <>drawValues; //var <>xAxisName, <>yAxisName; @@ -20,7 +62,7 @@ ScatterView2 { var selectionRect; var <>action; - var <>mouseDownAction, <>mouseUpAction, <>mouseMoveAction, mouseDownAction, <>mouseUpAction, <>mouseMoveAction, Date: Wed, 21 Nov 2018 15:50:36 +0100 Subject: [PATCH 2/6] added grid lines & small fixed --- classes/gui/ScatterView.sc | 389 ++++++++++++++++++++++--------------- 1 file changed, 234 insertions(+), 155 deletions(-) diff --git a/classes/gui/ScatterView.sc b/classes/gui/ScatterView.sc index e284348..47ef02a 100644 --- a/classes/gui/ScatterView.sc +++ b/classes/gui/ScatterView.sc @@ -5,16 +5,16 @@ and later... (C) 2018 Jonathan Reus / IEM Graz - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - For more details see: https://www.gnu.org/licenses/ +For more details see: https://www.gnu.org/licenses/ **********************************************************************/ @@ -25,24 +25,45 @@ A simple 2-dimensional scatterplot with coordinate axes. @usage +( +// Generate some toy data with a linear relationship n = 100; x = Array.series(n, 0.0, 100 / n) + Array.fill(n, {rrand(-10.0, 10.0)}).round(0.01); y = Array.series(n, 1.0, 100 / n) + Array.fill(n, {rrand(-10.0, 10.0)}).round(0.01); p = x.collect {|item,i| [item, y[i]] }; // as points +// Plot b = Rect(0,0, 800, 600); w = Window.new(bounds: b); j = ScatterView.new(w, b, p, [0,100].asSpec, [0,100].asSpec); -j.drawAxis_(true).symbolColor_(Color.blue).drawMethod_(\fillOval).symbolSize_(5@5); +j.symbolColor_(Color.blue).drawMethod_(\fillOval).symbolSize_(5@5); w.front; +); + +// Show axis, grid and value labels +j.drawAxes_(true).drawGrid_(true).drawValues_(true).refresh; + +// Visual style +j.axisColor_(Color.gray(0.3)).gridColor_(Color.red).valuesColor_(Color.gray(0.7)).backgroundColor_(Color.black).refresh; + + +// Adjust axes & scale +j.setAxes([-50, 150, \lin].asSpec, [-50,150,\lin].asSpec).symbolSize_(3@3).drawValues_(false).refresh; +j.setAxes([1, 150, \exp].asSpec, [0, 100,\lin].asSpec).symbolSize_(5@5).drawGridValues_(true).refresh; + */ ScatterView { - var background; - var <>highlightColor, highlightSize, <>isHighlight, <>drawAxis, <>drawValues; + var backgroundColor; + var <>highlightColor, highlightSize, <>isHighlight; + var <>drawAxes, <>drawGrid, <>drawGridValues, <>drawValues; + var <>xGridResolution, <>yGridResolution; + var <>axisColor,<>gridColor, <>valuesColor; var <>xAxisName, <>yAxisName; var symbolColor, <>drawMethod = \lineTo; - var specX, <>specY; + + var Date: Thu, 22 Nov 2018 16:06:59 +0100 Subject: [PATCH 3/6] added ScatterPlotter for plotting simultaneous data sets --- classes/gui/ScatterView.sc | 199 +++++++++++++++++++++++++++++-------- 1 file changed, 155 insertions(+), 44 deletions(-) diff --git a/classes/gui/ScatterView.sc b/classes/gui/ScatterView.sc index 47ef02a..5ed2625 100644 --- a/classes/gui/ScatterView.sc +++ b/classes/gui/ScatterView.sc @@ -26,17 +26,15 @@ A simple 2-dimensional scatterplot with coordinate axes. @usage ( -// Generate some toy data with a linear relationship n = 100; -x = Array.series(n, 0.0, 100 / n) + Array.fill(n, {rrand(-10.0, 10.0)}).round(0.01); -y = Array.series(n, 1.0, 100 / n) + Array.fill(n, {rrand(-10.0, 10.0)}).round(0.01); -p = x.collect {|item,i| [item, y[i]] }; // as points - -// Plot -b = Rect(0,0, 800, 600); -w = Window.new(bounds: b); -j = ScatterView.new(w, b, p, [0,100].asSpec, [0,100].asSpec); -j.symbolColor_(Color.blue).drawMethod_(\fillOval).symbolSize_(5@5); +x = Array.series(n, 0, 100 / n) + Array.fill(n, {rrand(-15.0, 15.0)}); +y = Array.series(n, 0, 100 / n) + Array.fill(n, {rrand(-15.0, 15.0)}); +p = x.collect {|item,i| [item, y[i]] }; + +w = Window.new("Linear Scatter", 800@600); +j = ScatterView.new(w, 800@600, p, [0,100].asSpec,[0,100].asSpec); +j.drawAxes_(true).drawGrid_(true).drawMethod_(\fillOval); +j.symbolSize_(5@5).symbolColor_(Color.blue); w.front; ); @@ -53,11 +51,11 @@ j.setAxes([1, 150, \exp].asSpec, [0, 100,\lin].asSpec).symbolSize_(5@5).drawGrid */ -ScatterView { +ScatterView : View { var backgroundColor; var <>highlightColor, highlightSize, <>isHighlight; var <>drawAxes, <>drawGrid, <>drawGridValues, <>drawValues; - var <>xGridResolution, <>yGridResolution; + var <>gridResolution; var <>axisColor,<>gridColor, <>valuesColor; var <>xAxisName, <>yAxisName; var symbolColor, <>drawMethod = \lineTo; @@ -66,11 +64,11 @@ ScatterView { var Date: Fri, 23 Nov 2018 15:12:47 +0100 Subject: [PATCH 4/6] small updates --- classes/gui/ScatterView.sc | 252 ++++++++++++++++++++----------------- 1 file changed, 136 insertions(+), 116 deletions(-) diff --git a/classes/gui/ScatterView.sc b/classes/gui/ScatterView.sc index 5ed2625..043f1b4 100644 --- a/classes/gui/ScatterView.sc +++ b/classes/gui/ScatterView.sc @@ -5,6 +5,9 @@ and later... (C) 2018 Jonathan Reus / IEM Graz +Views for Cartesian point / scatterplots + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or @@ -18,6 +21,122 @@ For more details see: https://www.gnu.org/licenses/ **********************************************************************/ + +/* +@class ScatterPlotter + +A higher level view abstraction that manages multiple scatterplots on a single graph. +All scatterplots share a single axis specification and commands for drawing / showing axes. + +@usage + +n = 100; +x = Array.series(n, 0, 100 / n) + Array.fill(n, {rrand(-15.0, 15.0)}); +y = Array.series(n, 0, 100 / n) + Array.fill(n, {rrand(-15.0, 15.0)}); +p = x.collect {|item,i| [item, y[i]] }; +x = Array.series(n, 0, 100 / n) + Array.fill(n, {rrand(-15.0, 15.0)}); +y = Array.series(n, 0, 100 / n).reverse + Array.fill(n, {rrand(-15.0, 15.0)}); +q = x.collect {|item,i| [item, y[i]] }; + +w = Window.new("X Scatter", 800@600); +j = ScatterPlotter.new(w, 800@600, p, [0,100].asSpec, [0,100].asSpec); +j.drawAxes_(true).drawGrid_(true).drawMethod_(\fillOval).symbolSize_(5@5); +w.front; + +j.addPlot(q); +j.addPlot([[0,0],[100,100]]); +j.backgroundColor_(Color.black).axisColor_(Color.gray); +j.symbolColor_(Color.blue,0); +j.symbolColor_(Color.green,1); +j.symbolColor_(Color.red,2).drawMethod_(\lineTo,2).symbolSize_(1,2); +j.setAxes([1,100,\exp].asSpec, [1,100,\exp].asSpec); + +// different random distributions +o = ScatterPlotter.new(nil, 800@400, Array.fill(100, {|i| [0.5.gauss(0.17), 0.3]})); +o.drawMethod_(\fillOval).drawAxes_(true).symbolSize_(3@3); +o.addPlot(Array.fill(100, {|i| [(0.5.bilinrand + 0.5), 0.5]})); +o.addPlot(Array.fill(100, {|i| [(0.5.sum3rand + 0.5), 0.7]})); +o.front; +*/ +ScatterPlotter : CompositeView { + var axisColor,<>gridColor, <>valuesColor; var <>xAxisName, <>yAxisName; var symbolColor, <>drawMethod = \lineTo; + var <>constrainToBounds; var Date: Thu, 6 Dec 2018 12:49:13 +0100 Subject: [PATCH 5/6] improvements to ScatterView --- classes/gui/ScatterView.sc | 18 ++++++++++++------ classes/various/Matrix.sc | 6 ++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/classes/gui/ScatterView.sc b/classes/gui/ScatterView.sc index 043f1b4..589dfd4 100644 --- a/classes/gui/ScatterView.sc +++ b/classes/gui/ScatterView.sc @@ -60,13 +60,15 @@ o.front; */ ScatterPlotter : CompositeView { var constrainToAxes; // boolean, if true points are constrained to visible axes - *new {|parent, bounds, data, specX, specY| - ^super.new(parent, bounds).init(data, specX, specY); + *new {|parent, bounds, data, specX, specY, constrain=false| + ^super.new(parent, bounds).init(data, specX, specY, constrain); } - init {|data, specX, specY| + init {|data, specX, specY, constrain| var firstplot; + constrainToAxes = constrain; scatterviews = List.new; firstplot = ScatterView.new(this, this.bounds, data, specX, specY); scatterviews.add(firstplot); @@ -118,11 +120,15 @@ ScatterPlotter : CompositeView { setAxes {|xspec, yspec| scatterviews.do {|plot, idx| - plot.setAxes(xspec, yspec); + plot.setAxes(xspec, yspec, constrainToAxes); plot.refresh; }; } + setAxesLabels {|xlabel, ylabel| + scatterviews[0].xAxisName_(xlabel).yAxisName_(ylabel).refresh; + } + data {|idx=0| ^scatterviews[idx].originalData } data_ {|thedata, idx=0, constrainToBounds=false| scatterviews[idx].data_(thedata, constrainToBounds).refresh; @@ -189,10 +195,10 @@ ScatterView : View { *drawMethods { ^[\fillRect, \fillOval, \strokeOval, \strokeRect] } - setAxes {|xspec,yspec| + setAxes {|xspec,yspec,constrainToBounds| specX = xspec ? specX; specY = yspec ? specY; - this.normalizeData; + this.normalizeData(constrainToBounds); } highlightItem_{|item| diff --git a/classes/various/Matrix.sc b/classes/various/Matrix.sc index e5bab89..f9e7a6a 100644 --- a/classes/various/Matrix.sc +++ b/classes/various/Matrix.sc @@ -122,8 +122,10 @@ Matrix[slot] : Array { }); } // single elements - at { arg row, col; - ^super.at(row).at(col); + at { arg row, col=nil; + var r = super.at(row); + if(col.notNil) { r = r.at(col) }; + ^r; } get { arg row, col; // same as at ^super.at(row).at(col); From 16b9166b1da4077799156d7fa88fcb6fde7b5889 Mon Sep 17 00:00:00 2001 From: jreus Date: Tue, 10 Dec 2019 15:24:26 +0100 Subject: [PATCH 6/6] final edits --- .gitignore | 1 + classes/Datasets/Transforms.sc | 122 +++++++++++++++++++++++++++++++++ classes/various/Matrix.sc | 45 +++++++++--- 3 files changed, 159 insertions(+), 9 deletions(-) create mode 100644 .gitignore create mode 100644 classes/Datasets/Transforms.sc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/classes/Datasets/Transforms.sc b/classes/Datasets/Transforms.sc new file mode 100644 index 0000000..f2daee0 --- /dev/null +++ b/classes/Datasets/Transforms.sc @@ -0,0 +1,122 @@ +/***************************************** +Data Transforms +(C) 2018 Jonathan Reus + +Tools for analyzing and transforming datasets: scaling, normalization, standardization, PCA, etc.. + + +******************************************/ + +// TO NORMALIZE: +// find min / max of features +// normalized_value = (val - min) / (max - min) + + +/* +T for Transform +Normalization: +1. find min/max of each feature +2. normalized_value = (val - min) / (max - min) +*/ +TNormalizer { + var 0) { res.putRow(row, func.value(this.at(row))) }; + }); + ^res; + } + + // collect columns, where column length of the new matrix is arbitrary + collectCols {arg func; + var res, firstCol; + if(this.cols<1) { ^this }; + firstCol = func.value(this.getCol(0), 0); + res = Matrix.newClear(firstCol.size, this.cols); + res.putCol(0, firstCol); + this.cols.do({arg col; + if(col>0) { res.putCol(col, func.value(this.getCol(col))) }; + }); + ^res; + } + addRow { arg rowVals; var res; - if( (rowVals.flat.size == this.cols) - .and(rowVals.every({arg element; element.isNumber}) ),{ + if( (this.rows == 0).or((rowVals.flat.size == this.cols) + .and(rowVals.every({arg element; element.isNumber}))), { res = this.copy; res = res.add(rowVals); - ^res},{ + ^res }, { error("wrong type or size in Matrix-addRow");this.halt; }); } + insertRow { arg col, rowVals; var res; if( (rowVals.flat.size == this.cols) @@ -215,8 +242,8 @@ Matrix[slot] : Array { } addCol { arg colVals; var res; - if( (colVals.flat.size == this.rows) - .and(colVals.every({arg element; element.isNumber}) ),{ + if( (this.rows == 0).or((colVals.flat.size == this.rows) + .and(colVals.every({arg element; element.isNumber}))), { res = Matrix.newClear(this.rows, this.cols+1); res.rows.do({ arg row; var rowArray; @@ -224,7 +251,7 @@ Matrix[slot] : Array { rowArray = rowArray.add(colVals.at(row)); res.putRow( row, rowArray); }); - ^res},{ + ^res}, { error("wrong type or size in Matrix-addCol");this.halt; }); }