Skip to content

Commit

Permalink
Merge pull request #4 from KxSystems/release/1.1.0
Browse files Browse the repository at this point in the history
Release/1.1.0
  • Loading branch information
mattmaynes committed Jul 23, 2019
2 parents 179c8b5 + 34dc11a commit fb57887
Show file tree
Hide file tree
Showing 32 changed files with 512 additions and 477 deletions.
36 changes: 19 additions & 17 deletions readme.md → README.md
Expand Up @@ -18,9 +18,8 @@ Getting this repository
This repository can be cloned directly into Kx Analyst or Kx Developer. Right-click the
workspace area on the left of the page and select `Git > Clone...`. In the dialog, enter
the URL for the training repository `https://github.com/kxsystems/analyst-training.git`.
Pressing `Ok` will open the `Pull Repository` dialog with the option to select a name
and branch for the repository. Press `Ok` to finish cloning the repository.

Pressing `OK` will open the `Pull Repository` dialog with the option to select a name
and branch for the repository. Press `OK` to finish cloning the repository.

Organization
------------
Expand All @@ -43,40 +42,43 @@ Resources

For more resources, please refer to the following links.

### Analyst
### Kx Analyst

- [Home page](https://kx.com/solutions/the-enterprise/analyst/)
- [User guide](https://code.kx.com/analyst/)
- [Kx Analyst home](https://kx.com/solutions/the-enterprise/analyst/) - Full featured interactive development environment for q and kdb+
- [Kx Analyst user guide](https://code.kx.com/analyst/) - Product documentation and example use cases

#### Visual Data Transformer and Query


- (*blog*) [Data Transformer](https://kx.com/blog/kx-product-insights-modern-data-preparation-etl-in-analyst-for-kx/)
- (*video*) [Data Transformer](https://vimeo.com/183895691)
- (*video*) [Visual Query in Transformer](https://vimeo.com/184708019)
- (*blog*) [Kx Product Insights: Modern Data Preparation (ETL) in Kx Analyst](https://kx.com/blog/kx-product-insights-modern-data-preparation-etl-in-analyst-for-kx/)
- (*video*) [Data Transformer overview](https://vimeo.com/183895691)
- (*video*) [Filtering data without programming using the Transformer](https://vimeo.com/184708019)

#### Visualization

- (*blog*) [Visualization for Exploratory Data Analysis](https://kx.com/blog/kx-product-insights-visualization-for-exploratory-data-analysis-eda/)
- (*video*) [Visual Inspector](https://vimeo.com/183886181)
- (*blog*) [Visualization for exploratory data analysis](https://kx.com/blog/kx-product-insights-visualization-for-exploratory-data-analysis-eda/)
- (*video*) [Visual Inspector overview](https://vimeo.com/183886181)
- (*video*) [Custom Graphics with q Visualization Library](https://vimeo.com/212133060)

#### Spreadsheet

- (*video*) [Spreadsheet](https://vimeo.com/183891867)
- (*video*) [Spreadsheet overview](https://vimeo.com/183891867)

### Developer
### Kx Developer

- [User guide](https://code.kx.com/developer/)
- [Kx Developer user guide](https://code.kx.com/developer/) - Product documentation and example use cases

#### IDE

- (*blog*) [IDE Overview](https://kx.com/blog/kx-product-insights-analyst-for-kx-ide/)
- (*video*) [IDE Overview](https://vimeo.com/239703330)
- (*blog*) [Kx Product Insights: IDE Overview](https://kx.com/blog/kx-product-insights-analyst-for-kx-ide/)
- (*video*) [IDE overview](https://vimeo.com/239703330)

#### Testing

- (*blog*) [Testing with qCumber and QuickCheq](https://kx.com/blog/kx-product-insights-testing-using-analyst-for-kx/)
- (*blog*) [Kx Product Insights: Testing with qCumber and QuickCheq](https://kx.com/blog/kx-product-insights-testing-using-analyst-for-kx/)
- (*video*) [Testing with qCumber and QuickCheq](https://vimeo.com/221903630)
- (*video*) [Behavioural Driven Development](https://vimeo.com/183916767)

### Demos

- (*video*) [Kx Developer and Kx Analyst: Live demo of a data driven project using taxi data](https://www.youtube.com/watch?v=o3Sg_RHnUdw)
Expand Up @@ -5,6 +5,11 @@ feature filterReadings
2 ~ count filterReadings[5] ([] x : til 10)

property should filter readings of any table
// Apply a quickcheq propery of 2 inputs (using `forall2`) where
// the first input is an integer from 0-5 and the second input is
// a table of anything. This will run the test property (the function)
// 100 times with random combinations of inputs to try and prove that
// the property holds or does not.
.qch.check .qch.forall2[.qch.g.int 5; .qch.g.table[]]{
if[x = 0; : .qch.discard];
(ceiling count[y] % x) ~ count filterReadings[x; y]
Expand Down
8 changes: 8 additions & 0 deletions kxscm/module/A.Tutorial.Data/qfn/gen.pulse
@@ -1,3 +1,11 @@
// @private
// @fileOverview
// Generate a single signal pulse for a sensor
// @param scale {timespan} time scale of pulse
// @param range {tuple (float; float)} boundaries of pulse
// @param pulse {float} size of pulse
// @param width {timespan} time width of pulse
// @return {table} generated sensor reading with a pulse
{[scale; range; pulse; width]
time : first[range] + ("j"$scale) * til "j"$(last[range] - first range) div "j"$scale;
signal : ([] time: time; signal: 4 mavg count[time]?0.1);
Expand Down
9 changes: 9 additions & 0 deletions kxscm/module/A.Tutorial.Data/qfn/gen.pulses
@@ -1,3 +1,12 @@
// @private
// @fileOverview
// Generate multiple pulses for a sensor
// @param scale {timespan} time scale of pulse
// @param pulse {float} size of pulse
// @param pulseWidth {timespan} time width of pulse
// @param repeatWidth {timespan} time between pulses
// @param n {long} number of readings
// @return {table} generated sensor reading with a pulses
{[scale; pulse; pulseWidth; repeatWidth; n]
: raze gen.pulse[scale;;pulse;pulseWidth] each x ,' (-1 _ next x:repeatWidth * til n),n * repeatWidth
}
4 changes: 0 additions & 4 deletions kxscm/module/A.Tutorial.Data/qfn/gen.wave

This file was deleted.

6 changes: 6 additions & 0 deletions kxscm/module/A.Tutorial.Data/qfn/sim.machine
@@ -1,3 +1,9 @@
// @private
// @fileOverview
// Simulates the readings for a single machine
// @param label {symbol} label to apply to machine
// @param n {long} number of readings to generate
// @return {table}
{[label; n]
sensors: raze {`$(string[x],"_"),/:.Q.a} each `temp`pressure`weight;
: raze {[n; sensor]
Expand Down
5 changes: 5 additions & 0 deletions kxscm/module/A.Tutorial.Data/qfn/sim.sensor
@@ -1,3 +1,8 @@
// @private
// @fileOverview
// Generate a number of signals for a given sensor
// @param n {long} the number of pulses
// @return {float[]} generated sensor readings
{[n]
: gen.pulses[0D00:00:00.02; 0.75; rand 0D00:00:40.0; 0D00:01:00.0; n];
}
7 changes: 7 additions & 0 deletions kxscm/module/A.Tutorial.Data/qfn/sim.system
@@ -1,3 +1,10 @@
// @fileOverview
// Runs a simulation of a sensor based system with some different machines
// and sensors. The values for these sensors are randomly generated values
// between 0 and 1. The simulation takes a few seconds and will produce
// approximately 10-15 million records.
//
// @return {table} simulated sensors data
{[]
labels : raze {`$(string[x],"_"),/:rand[26]#.Q.a} each `feed`mach`pkg;
readings : raze {sim.machine[x; 1 + rand 3]} each labels;
Expand Down
10 changes: 5 additions & 5 deletions kxscm/module/A.Tutorial.Doc/file/walkthrough.md
Expand Up @@ -14,7 +14,7 @@ it was moved to. To be able to access this data, we need to move the process to
directory. Run the following line to move the the process to the workspace.

```q
system "cd ",.ws.wsDir[];
system "cd ",getenv `AX_WORKSPACE;
```

Data
Expand Down Expand Up @@ -144,7 +144,7 @@ Alternatively, the transformation can be run as a function by invoking the trans
// and the last argument is for the outputs. Providing null for both uses the defaults
// that were configured in the UI. A dictionary can be provided for each input or output
// that maps the name of the node in the UI to a new input or output configuration.
ImportSensors[::;::]
ImportSensors[::;::];
// Example with explicit input and output locations
ImportSensors[
Expand Down Expand Up @@ -247,9 +247,9 @@ a closer look at this signal. We can use quick plotting library that included wi
// Select only sensor that is failing. Replace the query keys with the ones from
// the tooltip in the visual inspector.
//
// Replace the `mach_g` value with the machine name and the `pressure_a` with the
// Replace the `mach_a` value with the machine name and the `pressure_a` with the
// sensor name from the tooltip in the Visual Inspector
failing: select from sensors where machine=`mach_g, sensor=`pressure_a;
failing: select from sensors where machine=`mach_a, sensor=`pressure_a;
.qp.go[800; 500] plotSignal failing
```

Expand All @@ -271,7 +271,7 @@ reduce the noise in the plot.

```q
smooth: smoothReadings[10] firstId;
.qp.go[800;500] plotSignal smooth;
.qp.go[800;500] plotSignal smooth
```

Let's take a look at one last facet of the data. We can use the Grammar of Graphics to
Expand Down
102 changes: 51 additions & 51 deletions kxscm/module/B.Section.GrammarOfGraphics/file/Advanced/A-Settings.md
Expand Up @@ -6,66 +6,66 @@ yet been discussed are introduced here.

```q
// Grouping can split categories into separate subplots
.qp.go[700;400] .qp.area[subset; `time; `signal; ::];
.qp.go[700;400] .qp.area[subset; `time; `signal]
.qp.s.aes[`group`fill; `sensor`sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat20];
// When grouping, many geometries provide the ability to accommodate the groups by
// stacking or dodging (bars, area, etc)
// Grouping can split categories into separate subplots
.qp.go[700;400] .qp.area[subset; `time; `signal; ::];
.qp.go[700;400] .qp.area[subset; `time; `signal]
.qp.s.aes[`group`fill; `sensor`sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat20];
.qp.go[700;400] .qp.area[subset; `time; `signal]
.qp.s.aes[`group`fill; `sensor`sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat20]
, .qp.s.geom[enlist[`position]!enlist `stack];
// When grouping, many geometries provide the ability to accommodate the groups by
// stacking or dodging (bars, area, etc)
// Any frame can be converted to polar coordinates to produce new plots
.qp.go[700;400] .qp.point[subset; `signal; `time; ]
.qp.s.aes[`group`fill; `sensor`sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat20];
.qp.go[700;400] .qp.area[subset; `time; `signal]
.qp.s.aes[`group`fill; `sensor`sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat20]
, .qp.s.geom[enlist[`position]!enlist `stack];
// Any frame can be converted to polar coordinates to produce new plots
.qp.go[700;400] .qp.point[subset; `signal; `time; ]
.qp.s.aes[`group`fill; `sensor`sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat20];
// ... by just choosing polar coordinates
.qp.go[700;400] .qp.point[subset; `signal; `time; ]
.qp.s.aes[`group`fill; `sensor`sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat20]
, .qp.s.coord[.gg.coords.polar];
// ... by just choosing polar coordinates
// ... when doing this, keeping the frame aspect ratio as a square is a good idea
.qp.go[700;400] .qp.point[subset; `signal; `time; ]
.qp.go[700;400]
.qp.theme[enlist[`aspect_ratio]!enlist `square]
.qp.point[subset; `signal; `time; ]
.qp.s.aes[`group`fill; `sensor`sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat20]
, .qp.s.coord[.gg.coords.polar];
// ... when doing this, keeping the frame aspect ratio as a square is a good idea
// With a bit of cleverness, it is possible to create standard charts such as pie charts
.qp.go[700;400]
.qp.theme[enlist[`aspect_ratio]!enlist `square]
.qp.point[subset; `signal; `time; ]
.qp.s.aes[`group`fill; `sensor`sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat20]
, .qp.s.coord[.gg.coords.polar];
// With a bit of cleverness, it is possible to create standard charts such as pie charts
.qp.go[700;400]
.qp.theme[enlist[`aspect_ratio]!enlist `square]
.qp.bar[select y:0, count i by sensor from subset; `y; `x]
.qp.s.coord[.gg.coords.polar]
, .qp.s.geom[`size`position!(1000; `stack)]
, .qp.s.aes[`group; `sensor]
, .qp.s.aes[`fill; `sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat10]
, .qp.s.scale[`y; .gg.scale.extend[0b] .gg.scale.limits[0 0N] .gg.scale.linear];
// But we are not *limited* to only pies
.qp.go[700;400]
.qp.theme[enlist[`aspect_ratio]!enlist `square]
.qp.hbar[select y:0, avg signal by sensor from subset; `signal; `sensor]
.qp.s.coord[.gg.coords.polar]
, .qp.s.aes[`fill; `sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat10];
.qp.go[700;400]
.qp.theme[enlist[`aspect_ratio]!enlist `square]
.qp.bar[select y:0, count i by sensor from subset; `y; `x]
.qp.s.coord[.gg.coords.polar]
, .qp.s.geom[`size`position!(1000; `stack)]
, .qp.s.aes[`group; `sensor]
, .qp.s.aes[`fill; `sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat10]
, .qp.s.scale[`y; .gg.scale.extend[0b] .gg.scale.limits[0 0N] .gg.scale.linear];
// But we are not *limited* to only pies
.qp.go[700;400]
.qp.theme[enlist[`aspect_ratio]!enlist `square]
.qp.hbar[select y:0, avg signal by sensor from subset; `signal; `sensor]
.qp.s.coord[.gg.coords.polar]
, .qp.s.aes[`fill; `sensor]
, .qp.s.scale[`fill; .gg.scale.colour.cat10];
```

Other settings have already been discussed in the Basic sections, or will
Expand Down
Expand Up @@ -9,12 +9,12 @@ but are required to be stacked with another layer.

```q
.qp.go[500;300] .qp.stack (
.qp.hline[.8; .qp.s.geom[enlist[`fill]!enlist .gg.colour.Gold]];
.qp.hline[.5; .qp.s.geom[enlist[`fill]!enlist .gg.colour.Gold]];
.qp.vline[0D00:01:11.999; .qp.s.geom[`size`fill!(3; .gg.colour.FireBrick)]];
.qp.point[subset; `time; `signal]
.qp.s.geom[`size`alpha!(1; 0xf0)])
.qp.go[500;300] .qp.stack (
.qp.hline[.8; .qp.s.geom[enlist[`fill]!enlist .gg.colour.Gold]];
.qp.hline[.5; .qp.s.geom[enlist[`fill]!enlist .gg.colour.Gold]];
.qp.vline[0D00:01:11.999; .qp.s.geom[`size`fill!(3; .gg.colour.FireBrick)]];
.qp.point[subset; `time; `signal]
.qp.s.geom[`size`alpha!(1; 0xf0)])
```

Expand Down
Expand Up @@ -6,23 +6,19 @@ Statistical transforms apply a function to the data *before* plotting it.
Some geometries come bundled with a default stat transform.

```q
// A histogram is a bar geometry paired with a 1D binning transform
.qp.go[500;200] .qp.histogram[subset; `signal; ::];
// This can be recreated as...
.qp.go[500;200] .qp.bar[subset; `signal; `count__]
.qp.s.stat[ .gg.stat.bin1d[`signal; ::; .st.a.count[]; ::] ];
// A histogram is a bar geometry paired with a 1D binning transform
.qp.go[500;200] .qp.histogram[subset; `signal; ::];
// The `histogram` wrapper takes care of setting sizes and scales for you
.qp.go[500;200] .qp.bar[subset; `signal; `count__]
.qp.s.stat[ .gg.stat.bin1d[`signal; (`w;100;0); .st.a.count[]; ::] ]
, .qp.s.geom[enlist[`size]!enlist 100]
, .qp.s.scale[`y; .gg.scale.linear];
// This can be recreated as...
.qp.go[500;200] .qp.bar[subset; `signal; `count__]
.qp.s.stat[ .gg.stat.bin1d[`signal; ::; .st.a.count[]; ::] ];
// The `histogram` wrapper takes care of setting sizes and scales for you
.qp.go[500;200] .qp.bar[subset; `signal; `count__]
.qp.s.stat[ .gg.stat.bin1d[`signal; (`w;100;0); .st.a.count[]; ::] ]
, .qp.s.geom[enlist[`size]!enlist 100]
, .qp.s.scale[`y; .gg.scale.linear];
```

A stat transform can be applied to any layer. The available built-in transforms
Expand All @@ -35,14 +31,12 @@ grid, where each grid cell is split further into a series of segments depicting
the duration distribution within the cell.

```q
.qp.go[500;500] .qp.tile[subset; `signal; `sensor]
.qp.s.stat[ .gg.stat.binNd[`ma`sensor`signal; ((`c;50;0); (`w;1;0); (`c;50;0)); .st.a.count[]; ::] ]
, .qp.s.aes [`group; `signal]
, .qp.s.geom [`width`height`position!(50; 50; `dodge)]
, .qp.s.aes [`fill; `ma]
, .qp.s.scale [`fill; .gg.scale.colour.gradient . .gg.colour`SteelBlue`FireBrick]
, .qp.s.aes [`alpha; `count__]
, .qp.s.scale [`alpha; .gg.scale.alpha[50; 255]];
.qp.go[500;500] .qp.tile[subset; `signal; `sensor]
.qp.s.stat[ .gg.stat.binNd[`ma`sensor`signal; ((`c;50;0); (`w;1;0); (`c;50;0)); .st.a.count[]; ::] ]
, .qp.s.aes [`group; `signal]
, .qp.s.geom [`width`height`position!(50; 50; `dodge)]
, .qp.s.aes [`fill; `ma]
, .qp.s.scale [`fill; .gg.scale.colour.gradient . .gg.colour`SteelBlue`FireBrick]
, .qp.s.aes [`alpha; `count__]
, .qp.s.scale [`alpha; .gg.scale.alpha[50; 255]];
```

0 comments on commit fb57887

Please sign in to comment.