class:: Plotter summary:: Plot numerical data on a window or view categories:: GUI>Accessories related:: Reference/plot description:: Plot data of up to three dimensions on a link::Classes/Window:: or link::Classes/UserView::. subsection:: Keyboard shortcuts When the plotter window has focus, the following keyboard shortcuts can be used to change the display: table:: ## + / - || vertical zoom ## = || compare plot channels ## n || toggle normalize display (0..1) / (-1..1), or fit range ## s || toggle superposition (see: superpose) ## m || switch plot mode (see: link::Classes/Plotter#-plotMode::) ## e || toggle editing (see: link::Classes/Plotter#-editMode::) ## g || toggle horizontal (domain) grid ## G || toggle vertical (codomain) grid ## p || print curve ## ctrl-+ / - || zoom font ## alt-click || post value :: subsection:: Method extensions Plotter extends other classes with methods. To see what classes implements plot, see link::Overviews/Methods#plot:: method:: plot (args) code:: // plot array [1, 6, 2, -5, 2].plot; (0..100).normalize(0, 8pi).sin.plot; // nested arrays { (0..100).normalize(0, 15.0.rand).sin }.dup(3).plot; { { (0..17).normalize(0, 15.0.rand).sin }.dup(4) }.dup(3).plot; // UGen functions { SinOsc.ar([700, 357]) * SinOsc.ar([400, 476]) * 0.2 }.plot; // Buffer Buffer.read(s, Platform.resourceDir +/+ "sounds/SinedPink.aiff").plot; // Env Env.perc(0.4, 0.6).plot; :: method:: plotGraph (n,from,to,...) code:: { |x| sin(x) }.plotGraph(300,0,2*pi); { |x| sin(1/x)*x }.plotGraph(from:0.0001,to:0.2); :: section:: Changing global defaults The default styles are kept (and may be overridden) in code::GUI.skin.at(\plot)::. See also link::Classes/GUI:: help. code:: // specify plot layout ( GUI.skin.plot.gridLinePattern = FloatArray[1, 0]; GUI.skin.plot.fontColor = Color(0.5, 1, 0); GUI.skin.plot.gridColorX = Color.yellow(0.5); GUI.skin.plot.gridColorY = Color.yellow(0.5); GUI.skin.plot.background = Color.black; GUI.skin.plot.plotColor = (10..0).normalize(0.1, 1).collect { |i| Color.rand(i) }; GUI.skin.plot.labelX = "X"; GUI.skin.plot.labelY = "Y"; ); ( x = { |i| (0..60).scramble.clump(8) * (3.5 ** i) }.dup(3); x.plot("ARRAY:PLOT", Rect(200, 300, 600, 500)); ) GUI.skin.plot.put(\plotColor, { Color.rand(0.0, 0.8) } ! 8); [(0..100), (20..120), (40..140)].squared.flop.bubble.plot; // reset the defaults: Plot.initClass; :: classmethods:: method:: new argument:: name Plot window title. argument:: bounds The window bounds (a link::Classes/Rect::). argument:: parent Either a link::Classes/Window:: / link::Classes/View:: may be passed in - then the plot is embedded. Otherwise a new link::Classes/Window:: is created. discussion:: code:: ( a = Plotter("the plot", Rect(600, 30, 800, 250)); a.value = (0..1000).normalize(0, 14pi).curdle(0.01).scramble.flat.sin; ) :: instancemethods:: subsection:: Accessing Instance Variables method:: makeWindow Open given plotter in a new window or within a given composite view. argument:: argParent Either a link::Classes/Window:: or link::Classes/View:: may be passed in - then the plot is embedded. Otherwise a new link::Classes/Window:: is created. argument:: argBounds The window bounds (a link::Classes/Rect::). method:: plotMode Set the style of data display. argument:: symbol Available modes: table:: ## code::\linear:: || connecting data points with linear interpolation ## code::\points:: || draw data points only ## code::\plines:: || combination of lines and points ## code::\levels:: || horizontal lines ## code::\steps:: || connecting data points with step interpolation :: discussion:: code:: a = (0..20).scramble.plot; a.plotMode = \points; a.refresh; a.plotMode = \plines; a.refresh; a.plotMode = \levels; a.refresh; a.plotMode = \steps; a.refresh; a.plotMode = \linear; a.refresh; :: method:: setProperties Set properties of all plot views. Defaults are taken from code::GUI.skin.at(\plot);:: argument:: ... pairs A list of symbol,value pairs. Supported properties: list:: ## font ## fontColor ## gridColorX ## gridColorY ## plotColor (an link::Classes/Array::) ## backgroundColor ## gridLinePattern ## gridLineSmoothing ( link::Classes/Boolean:: ) ## labelX ## labelY ## gridOnX ( link::Classes/Boolean:: ) ## gridOnY ( link::Classes/Boolean:: ) :: discussion:: Example: code:: ( a = { (0..30).scramble }.dup(2).plot; a.setProperties( \fontColor, Color.red, \plotColor, Color.blue, \backgroundColor, Color.black, \gridColorX, Color.white, \labelX, "Humidity" ); a.refresh; ); GUI.skin.at(\plot); // defaults :: method:: editMode If the edit mode is set to true, the data may be edited via cursor. code:: a = (0..20).plot; a.editMode = true; // now edit the data by clicking into the plot.. a.value; // the value :: method:: resolution Set the number of data points displayed maximally per pixel (default: 1) code:: a = (0..200).scramble.plot; a.resolution = 8; a.refresh; // resizing the window shows interpolation a.resolution = 1; a.refresh; :: method:: findSpecs If true (default: code::true::), specs are derived from new data (using min and max values) automatically. method::superpose If set to true, plotter displays channels on top of each other (keyboard shortcut: s) code:: a = { (0..30).scramble }.dup(2).plot; a.superpose = true; a.refresh; :: method:: value Return or set the data values. Data may be numerical arrays of up to 3 dimensions. code:: a = [1, 4, 2, 7, 4].dup(2).plot; a.value; :: method:: data Reference to the current internal data. method:: cursorPos Returns:: the last cursorPos (a link::Classes/Point::). method:: plots Returns:: the single subplots (a link::Classes/Plot::). method:: specs Set or get the spec for the y-axis (codomain). code:: a = { (40..3000).scramble }.dup(2).plot; a.specs = \freq.asSpec; a.refresh; :: method:: domainSpecs Set or get the spec for the x-axis (domain). code:: a = { (40..300).scramble }.dup(2).plot; a.domainSpecs = \freq.asSpec; a.refresh; :: method:: editFunc Supply a function which is evaluated when editing data. The function is called with the arguments: code::plotter::, code::plotIndex::, code::index::, code::val::, code::x::, code::y::. discussion:: Example: code:: ( a = { (0..10).scramble.normalize }.dup(2).plot; a.editMode = true; a.editFunc = { |...args| args.postln }; ); // using plotter as a control interface ( a = (0..10).scramble.normalize(300, 400).plot; a.specs = \freq; a.plotMode = \points; a.editMode = true; x = { SinOsc.ar(\freq.kr(a.value)).mean * 0.1 }.play; a.editFunc = { |plotter, plotIndex, i, val| x.setn(\freq, a.value) }; a.parent.onClose = { x.release }; ); ( a = { (0..10).scramble.normalize(300, 400) }.dup.plot; a.specs = \freq; a.plotMode = \levels; a.editMode = true; x = { var phase = SinOsc.ar(\rate.kr(a.value[1])); SinOsc.ar(\freq.kr(a.value[0]), phase).mean * 0.1 }.play; a.editFunc = { |plotter, plotIndex, i, val| x.setn(\freq, a.value[0]); x.setn(\rate, a.value[1]); }; a.parent.onClose = { x.release }; ); :: examples:: code:: // embedding in another GUI ( w = Window("plot panel", Rect(20, 30, 520, 450)); Slider.new(w, Rect(10, 10, 490, 20)).resize_(2).action_ { |v| a.value = (0..(v.value.linexp(0, 1, 5, 8000)).asInteger).scramble; w.refresh; }; z = CompositeView(w, Rect(10, 35, 490, 400)).background_(Color.rand(0.7)).resize_(5); a = Plotter("plot", parent: z).value_([0, 1, 2, 3, 4].scramble * 100); w.front; ) ( a = Plotter("the plot", Rect(600, 30, 600, 400)); a.value = (0..100).normalize(0, 8pi).sin; ) a.value = { |i| (0..90) % (i + 12) + ( (0..90) % (i + 2 * 1) ) }.dup(3); a.value = (0..12).squared; a.plotMode = \points; a.refresh; a.plotMode = \levels; a.refresh; a.plotMode = \plines; a.refresh; a.domainSpecs = [[0, 115, \lin, 1]]; a.refresh; a.parent.close; // close window a.makeWindow; // open it again a.value = { (0..70).scramble }.dup(3); a.plotMode = \linear; a.refresh; a.value = { |i| (0..2000).normalize(0, 4pi + i).sin } ! 4; // lots of values, test efficiency a.value = { |i| (0..10000).normalize(0, 8pi + i).sin } ! 3; // lots of values, test efficiency a.value = { (0..140).scramble } ! 7; a.value = { |i| (0..90).normalize(0, 8pi + (i*2pi)).sin } ! 2 * [400, 560] + 700; a.value = { |i| (_ + 2.0.rand).dup(100).normalize(0, 8pi + i).sin } ! 2 * 400 + 700; // multi channel expansion of single values a.value = { |i| (_ + 2.0.rand).dup(100).normalize(0, 8pi + i).sin *.t [1, 2, 3] } ! 2 * 400 + 700; a.value = { |i| (0..10) **.t [1, 1.2, 1.3, 1.5] * (3.5 ** i) }.dup(3); a.parent.bounds = Rect(400, 100, 500, 700); a.parent.bounds = Rect(600, 30, 500, 300); a.superpose = true; a.value = { |i| (0..20) * (3.5 ** i) }.dup(5); a.superpose = false; // specs a.value = (50..90).midicps.scramble; a.specs = \freq; a.refresh; a.value = (1..60).scramble.neg; a.specs = \db; a.refresh; a.value = { |i| { exprand(1e3, (10 ** (i + 8))) }.dup(90) }.dup(3); a.value = { { exprand(1e3, 1e9) }.dup(90) }.dup(3); a.specs = [[1e3, 1e10, \exp], [1e3, 1e20, \exp], [1e3, 1e30, \exp]]; a.refresh; a.domainSpecs = [[0, 5], [-8, 100], [-1, 1]]; a.refresh; // Array:plot ( a = (4 ** (-5..0)).postln.plot; a.specs = \delay; a.refresh; a.domainSpecs = [0, 10, \lin, 0, 0, " Kg"].asSpec; a.refresh; ); a.domainSpecs = [0.1, 10, \exponential, 0, 0, " Kg"].asSpec; a.refresh; a.domainSpecs = [-10, 10, \lin, 0, 0, " Kg"].asSpec; a.refresh; a = [(0..100) * 9, (200..1300) * 2, (200..1000)/ 5].plot; a.superpose = true; a = [[0, 1.2, 1.5], [0, 1.3, 1.5, 1.6], [0, 1.5, 1.8, 2, 6]].midiratio.plot; a.plotMode = \levels; a.refresh; a.superpose = false; // Function:plot a = { SinOsc.ar([700, 357]) * SinOsc.ar([400, 476]) * 0.2 }.plot; a = { SinOsc.ar([700, 357] *0.02) * SinOsc.ar([400, 476]) * 0.3 }.plot(0.2, minval: -1); a = { SinOsc.ar(440) }.plot(1); // Env:plot Env.perc(0.4, 0.6).plot; Env.new({ 1.0.rand2 }! 8, { 1.0.rand } ! 7, \sin).plot; // Buffer:plot b = Buffer.read(s, Platform.resourceDir +/+ "sounds/SinedPink.aiff"); // Platform.resourceDir +/+ "sounds/SinedPink.aiff" contains SinOsc on left, PinkNoise on right b.plot; b.free; ::