├── .clj-kondo └── config.edn ├── .gitignore ├── INTERNALS.md ├── LICENSE ├── README.md ├── data ├── GvHD-FSC-H │ ├── s10a01 │ ├── s10a02 │ ├── s10a03 │ ├── s10a04 │ ├── s10a05 │ ├── s10a06 │ ├── s10a07 │ ├── s5a01 │ ├── s5a02 │ ├── s5a03 │ ├── s5a04 │ ├── s5a05 │ ├── s5a06 │ ├── s5a07 │ ├── s6a01 │ ├── s6a02 │ ├── s6a03 │ ├── s6a04 │ ├── s6a05 │ ├── s6a06 │ ├── s6a07 │ ├── s7a01 │ ├── s7a02 │ ├── s7a03 │ ├── s7a04 │ ├── s7a05 │ ├── s7a06 │ ├── s7a07 │ ├── s9a01 │ ├── s9a02 │ ├── s9a03 │ ├── s9a04 │ ├── s9a05 │ ├── s9a06 │ └── s9a07 ├── barley.json ├── cars.json ├── chem97.json ├── co2-concentration.csv ├── disasters.csv ├── driving.json ├── earthquake.json ├── faithful.json ├── gapminder-health-income.csv ├── gvhd10.json ├── laucnty17.csv ├── movies.json ├── nhanes.json ├── oats.json ├── population.json ├── postdoc.json ├── quakes.json ├── seattle-weather.csv ├── ssd.json ├── stocks.csv ├── sunspot_year.json ├── titanic.json ├── unemployment-across-industries.json └── usarrests.json ├── project.clj ├── resources └── clj-kondo.exports │ └── cljplot │ └── cljplot │ ├── config.edn │ └── hooks │ └── common.clj ├── results ├── anim │ └── res.gif ├── bar.jpg ├── bars.jpg ├── box.jpg ├── bubble.jpg ├── connected.jpg ├── cont4_cont8.jpg ├── density-line.jpg ├── density.jpg ├── examples │ ├── acf.jpg │ ├── complex.jpg │ ├── contour.jpg │ ├── contour2d.jpg │ ├── field-trace.jpg │ ├── field.jpg │ ├── function2d.jpg │ ├── gp-posterior.jpg │ ├── gp-posteriors-20.jpg │ ├── gp-predict.jpg │ ├── gp-priors-20.jpg │ ├── heatmap-matrix-ann.jpg │ ├── heatmap-matrix.jpg │ ├── heatmap.jpg │ ├── kernel-densities.jpg │ ├── lag.jpg │ ├── lines.jpg │ ├── logo.jpg │ ├── ma2.jpg │ ├── point-cloud.jpg │ ├── ppplot.jpg │ ├── qqplot.jpg │ ├── random-walk-wrapped.jpg │ ├── strips.jpg │ ├── vector-field.jpg │ └── vnoise.jpg ├── functions.jpg ├── histogram-percents.jpg ├── histogram.jpg ├── lattice │ ├── figure_1.1.jpg │ ├── figure_1.2.jpg │ ├── figure_1.3.jpg │ ├── figure_13.1.jpg │ ├── figure_13.2.jpg │ ├── figure_14.1.jpg │ ├── figure_14.2.jpg │ ├── figure_14.3.jpg │ ├── figure_14.4.jpg │ ├── figure_2.1.jpg │ ├── figure_2.10.jpg │ ├── figure_2.2.jpg │ ├── figure_2.3.jpg │ ├── figure_2.4.jpg │ ├── figure_2.6.jpg │ ├── figure_2.7.jpg │ ├── figure_2.8.jpg │ ├── figure_2.9.jpg │ ├── figure_3.1.jpg │ ├── figure_3.10.jpg │ ├── figure_3.11.jpg │ ├── figure_3.12.jpg │ ├── figure_3.13.jpg │ ├── figure_3.14.jpg │ ├── figure_3.15.jpg │ ├── figure_3.16.jpg │ ├── figure_3.2.jpg │ ├── figure_3.2v2.jpg │ ├── figure_3.3.jpg │ ├── figure_3.4.jpg │ ├── figure_3.5.jpg │ ├── figure_3.6.jpg │ ├── figure_3.7.jpg │ ├── figure_3.8.jpg │ ├── figure_3.9.jpg │ ├── figure_4.1.jpg │ ├── figure_4.2.jpg │ ├── figure_4.3.jpg │ ├── figure_4.4.jpg │ ├── figure_4.5.jpg │ ├── figure_4.6.jpg │ └── figure_4.7.jpg ├── line.jpg ├── lollipops.jpg ├── lollipops2.jpg ├── min-max-mean.jpg ├── rug.jpg ├── rugs.jpg ├── scatter-sides.jpg ├── scatters2-rug.jpg ├── strip-distorted.jpg ├── strip.jpg ├── vega │ ├── area-overlay.jpg │ ├── area.jpg │ ├── bar-aggregate.jpg │ ├── bar-color.jpg │ ├── bar-gantt.jpg │ ├── bar-grouped.jpg │ ├── bar.jpg │ ├── box-plot.jpg │ ├── circle-binned.jpg │ ├── circle-bubble-hi.jpg │ ├── circle-natural-disasters.jpg │ ├── circles.jpg │ ├── color-with-shape.jpg │ ├── connected-scatterplot.jpg │ ├── histogram.jpg │ ├── layer-line-co2-concentration.jpg │ ├── line-color.jpg │ ├── line-overlay.jpg │ ├── line-spline.jpg │ ├── line-step.jpg │ ├── line.jpg │ ├── nulls.jpg │ ├── point-bubble.jpg │ ├── point-errorbar-ci.jpg │ ├── point-errorbar-stddev.jpg │ ├── point2d.jpg │ ├── stacked-area-normalize.jpg │ ├── stacked-area-stream.jpg │ ├── stacked-area.jpg │ ├── stacked-bar-h.jpg │ ├── stacked-bar-layer.jpg │ ├── stacked-bar-normalize.jpg │ ├── stacked-bar-weather.jpg │ ├── table-binned-heatmap-marginal.jpg │ ├── table-binned-heatmap.jpg │ ├── text-scatterplot-colored.jpg │ ├── tick-dot.jpg │ ├── tick-strip.jpg │ └── trail-color.jpg ├── violin.jpg └── violins.jpg ├── sketches ├── bayesian_optimisation.clj ├── examples.clj ├── lattice.clj └── vega.clj └── src ├── cljplot ├── axis.clj ├── build.clj ├── common.clj ├── config.clj ├── core.clj ├── impl │ ├── free.clj │ ├── heatmap.clj │ ├── histogram.clj │ ├── label.clj │ ├── line.clj │ ├── math.clj │ ├── scatter.clj │ ├── strips.clj │ └── time_series.clj ├── render.clj └── scale.clj └── marchingsquares ├── Algorithm.java ├── Cell.java ├── Grid.java └── PathGenerator.java /.clj-kondo/config.edn: -------------------------------------------------------------------------------- 1 | {:config-paths ["../resources/clj-kondo.exports/cljplot/cljplot"]} 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | pom.xml 2 | pom.xml.asc 3 | *.jar 4 | *.class 5 | /lib/ 6 | /classes/ 7 | /target/ 8 | /checkouts/ 9 | .lein-deps-sum 10 | .lein-repl-history 11 | .lein-plugins/ 12 | .lein-failures 13 | .nrepl-port 14 | .cpcache/ 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CLJPLOT 2 | 3 | > **_INFO (2020-08-17):_** I'm preparing new version based on tech.ml.dataset as data input which is going to solve issues with data processing and labels. Also rethinking the way of better management of data dimensions and their representation through trellis/colors/axes etc. It happens very slowly, but happens. Stay tuned. 4 | 5 |

6 | logo 7 |

8 | 9 | # clojure2d.charts 10 | 11 | THIS IS WIP/POC 12 | A "no web-based" pure JVM Clojure library for 2d charts, inspired by D3, Vega and R (ggplot2/lattice/facet). 13 | 14 | ## Current version 15 | 16 | `[cljplot "0.0.3"]` 17 | 18 | ## NOTE about API 19 | 20 | Please note that current way of creating charts is very low level. All of this nasty steps will be finally hidden from user perspective. 21 | 22 | ## Usage 23 | 24 | Currently there are no easy to use functions nor data DSL (help needed here). Still everything is done manually. 25 | 26 | See `sketches` folder for examples 27 | 28 | ### Examples 29 | 30 |

31 | 32 | 33 | 34 | 35 | 36 | 37 |

38 | 39 |

40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |

50 | 51 |

52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |

62 | 63 | 64 | ## Short term plan 65 | 66 | * More chart types (`+` - easier; `-` - harder): 67 | - ~~heatmaps (various grids)~~ (`+`) 68 | - ~~point clouds (log and linear rendering)~~ (`+`) 69 | - ~~contours (`-`), flow fields (`+`)~~ 70 | - categorical x categorical plots (scatter plot matrix (`+`) 71 | - ~~stacked area/stream~~ 72 | - parallel / hive (`+`/`-`) 73 | - radial charts, like pie (`+`), sunburst (`-`), radial tree (`-`) 74 | - arc(?) (`+`) 75 | - markers: line, text, etc... 76 | * ~~Labels~~ / ~~legends~~ / gradients / palettes 77 | * Higher level API 78 | - single function for each chart type (easier) 79 | - faceting/lattice (harder) 80 | * cleaning configuration mess 81 | 82 | ## Long term plan / wishlist 83 | 84 | * Enable other renderers (create dispatch layer) 85 | * Data DSL(?) 86 | * geo maps 87 | * elements of UpSet 88 | * signal processing / time series (partially done) 89 | * annotations 90 | * grid of charts / subplots (with independent axes) 91 | * kind of interactivity 92 | * chart styles (now everything is blueish) 93 | 94 | ## Known issues 95 | 96 | * ~~grid, axes sometimes don't match (1-2px shift). This is due to rounding errors and axes rotations~~ 97 | * still ~~no labels~~, ~~no legends~~ 98 | * overlapping ticks (add some heuristics to use smaller fonts and smaller number of ticks) 99 | * chart configuration needs to be reviewed, still not consistent 100 | * no higher level functions/macros 101 | * no DSL for data manipulation, and no plan to make it (task for others!) 102 | * deep nesting is really nasty to configure and for data preparation :/ (lattice of stacked horizontally stacked bars...) 103 | * merging nested extents is not working correctly (in lattice) 104 | * true is, there are some labels for lattice, quick and dirty 105 | * do not layer over histograms (bins mismatch)... 106 | * still something is wrong with time scale 107 | 108 | ## Why? 109 | 110 | So, why another chart library, when you can use _insert any name here_ 111 | In my case, the main obstacle was the ability to save hundreds of charts without using any display (web or java frame). 112 | One can say: jfreechart! I can say: try to generate heatmaps... Every library I've found had some issues or produces ugly result or was web based or was notebook based or... 113 | So I fell into the lisp curse and I'm writing my own. 114 | 115 | ## Contributing 116 | 117 | YES! A lot of things to do: 118 | * documentation 119 | * configuration 120 | * new charts 121 | * testing, test-cases 122 | 123 | Let's chat about this: https://clojurians.zulipchat.com/#narrow/stream/197967-cljplot-dev 124 | 125 | ## Marching squares algorithm 126 | 127 | Source: https://udel.edu/~mm/code/marchingSquares/ 128 | 129 | ## License 130 | 131 | Copyright © 2019-2023 132 | 133 | Distributed under the Eclipse Public License either version 1.0 or (at 134 | your option) any later version. 135 | -------------------------------------------------------------------------------- /data/GvHD-FSC-H/s6a01: -------------------------------------------------------------------------------- 1 | [[137],[180],[60],[159],[112],[167],[238],[133],[179],[202],[232],[86],[119],[143],[103],[200],[185],[177],[78],[74],[182],[172],[203],[88],[132],[278],[240],[88],[171],[186],[120],[97],[161],[93],[96],[130],[203],[83],[144],[160],[293],[193],[222],[280],[91],[258],[217],[129],[212],[210],[194],[234],[78],[152],[66],[541],[550],[709],[180],[373],[588],[89],[84],[125],[137],[136],[60],[162],[101],[127],[128],[173],[133],[140],[141],[137],[560],[608],[158],[630],[80],[490],[409],[228],[266],[71],[507],[225],[769],[433],[973],[145],[146],[507],[625],[533],[431],[182],[448],[423],[132],[69],[522],[740],[137],[530],[65],[126],[661],[554],[342],[333],[1023],[666],[527],[303],[363],[604],[698],[606],[60],[487],[125],[543],[529],[575],[114],[92],[481],[561],[452],[827],[170],[153],[119],[234],[470],[178],[60],[68],[193],[70],[274],[176],[60],[65],[581],[383],[653],[666],[1023],[404],[456],[236],[409],[743],[72],[572],[539],[678],[366],[723],[62],[509],[336],[435],[152],[644],[938],[550],[515],[667],[567],[177],[179],[235],[519],[493],[237],[492],[708],[766],[394],[410],[138],[617],[431],[300],[463],[380],[165],[70],[520],[642],[681],[72],[61],[526],[368],[568],[86],[72],[61],[62],[490],[719],[573],[344],[1023],[674],[823],[87],[245],[249],[104],[553],[62],[67],[529],[138],[66],[532],[68],[530],[71],[516],[92],[67],[498],[147],[233],[65],[527],[108],[239],[67],[516],[320],[131],[276],[66],[522],[170],[67],[520],[74],[126],[122],[66],[575],[214],[242],[185],[145],[129],[249],[67],[129],[60],[188],[243],[176],[243],[229],[133],[216],[69],[178],[239],[252],[158],[164],[195],[211],[142],[156],[155],[95],[246],[79],[197],[242],[147],[149],[235],[136],[272],[69],[241],[313],[204],[155],[253],[190],[105],[210],[182],[264],[166],[251],[175],[150],[123],[205],[185],[94],[329],[270],[152],[95],[209],[284],[97],[251],[282],[81],[324],[333],[329],[248],[168],[151],[151],[263],[206],[173],[344],[311],[286],[240],[171],[211],[210],[151],[277],[258],[156],[194],[289],[188],[251],[253],[132],[245],[316],[224],[61],[163],[346],[181],[170],[258],[168],[158],[368],[239],[159],[137],[115],[286],[211],[177],[270],[276],[267],[124],[120],[331],[304],[229],[190],[159],[256],[151],[292],[195],[335],[316],[90],[183],[177],[272],[200],[195],[113],[203],[193],[155],[225],[147],[141],[349],[162],[189],[176],[84],[266],[155],[177],[162],[246],[203],[180],[165],[263],[69],[296],[207],[316],[262],[385],[260],[168],[313],[197],[251],[181],[295],[177],[240],[294],[113],[180],[196],[310],[194],[199],[214],[131],[200],[275],[168],[302],[209],[87],[267],[163],[273],[152],[223],[197],[181],[152],[78],[179],[189],[113],[246],[110],[185],[231],[307],[191],[62],[260],[297],[157],[248],[189],[260],[226],[110],[253],[264],[262],[163],[143],[191],[190],[188],[198],[303],[273],[198],[107],[247],[181],[204],[302],[150],[179],[209],[241],[191],[158],[187],[236],[343],[80],[179],[277],[169],[260],[193],[231],[305],[207],[329],[195],[230],[293],[76],[171],[414],[173],[230],[250],[330],[162],[151],[247],[303],[147],[166],[253],[329],[249],[110],[120],[205],[158],[187],[228],[124],[196],[284],[85],[172],[332],[221],[119],[215],[158],[155],[171],[372],[187],[128],[225],[171],[163],[189],[111],[192],[237],[196],[247],[208],[203],[144],[174],[192],[232],[105],[200],[217],[133],[74],[266],[158],[240],[224],[197],[182],[292],[346],[201],[400],[274],[146],[289],[206],[300],[303],[112],[149],[88],[165],[310],[215],[235],[136],[257],[167],[270],[156],[174],[166],[275],[285],[207],[249],[94],[63],[182],[231],[245],[210],[114],[180],[192],[69],[303],[175],[160],[196],[152],[302],[110],[207],[233],[217],[104],[165],[176],[127],[267],[287],[378],[179],[170],[169],[201],[107],[204],[260],[173],[216],[163],[245],[189],[301],[159],[249],[213],[254],[159],[234],[193],[190],[207],[151],[183],[157],[243],[184],[105],[203],[170],[321],[97],[339],[265],[157],[66],[350],[166],[176],[152],[286],[237],[478],[186],[196],[427],[144],[121],[94],[204],[282],[138],[189],[204],[186],[192],[221],[186],[175],[276],[186],[187],[82],[141],[262],[172],[271],[287],[173],[295],[305],[171],[170],[145],[105],[156],[207],[207],[205],[175],[155],[242],[178],[163],[172],[168],[206],[188],[204],[204],[172],[153],[165],[158],[146],[100],[216],[173],[161],[293],[315],[152],[134],[84],[284],[162],[144],[97],[179],[238],[170],[333],[172],[191],[184],[188],[346],[158],[255],[153],[185],[293],[272],[233],[390],[174],[148],[108],[238],[313],[187],[138],[166],[128],[194],[63],[245],[113],[162],[200],[402],[145],[130],[187],[164],[270],[144],[165],[208],[173],[167],[182],[70],[280],[190],[324],[201],[89],[341],[189],[167],[125],[193],[153],[179],[203],[108],[181],[280],[221],[85],[175],[95],[217],[183],[207],[305],[170],[196],[160],[211],[133],[211],[189],[262],[140],[174],[170],[185],[117],[266],[184],[244],[303],[144],[151],[252],[202],[135],[153],[205],[182],[245],[104],[173],[220],[194],[135],[156],[103],[186],[317],[263],[152],[241],[214],[190],[232],[302],[84],[247],[142],[222],[172],[79],[83],[125],[161],[255],[207],[177],[306],[137],[174],[171],[166],[162],[222],[279],[151],[162],[229],[141],[182],[182],[180],[170],[249],[146],[200],[107],[192],[201],[182],[212],[229],[257],[196],[83],[204],[167],[90],[186],[161],[193],[271],[242],[249],[200],[209],[217],[119],[285],[262],[283],[322],[185],[161],[152],[221],[166],[172],[134],[157],[86],[426],[314],[270],[156],[206],[170],[228],[259],[337],[251],[129],[308],[253],[171],[149],[95],[255],[156],[178],[162],[230],[266],[169],[352],[214],[135],[144],[208],[212],[213],[154],[195],[107],[382],[350],[321],[210],[172],[334],[117],[304],[143],[189],[79],[265],[190],[275],[288],[149],[331],[192],[189],[303],[143],[192],[199],[174],[181],[267],[175],[77],[210],[209],[164],[167],[233],[357],[173],[153],[165],[321],[71],[138],[81],[192],[140],[264],[209],[153],[259],[173],[191],[347],[291],[76],[213],[187],[213],[175],[148],[293],[216],[114],[143],[188],[191],[269],[103],[217],[280],[234],[125],[164],[205],[203],[272],[148],[107],[302],[316],[258],[250],[238],[174],[168],[120],[250],[151],[158],[344],[168],[210],[155],[326],[64],[187],[84],[236],[175],[133],[140],[63],[535],[557],[884],[568],[271],[464],[969],[446],[65],[260],[212],[205],[269],[98],[69],[191],[231],[166],[183],[228],[88],[267],[233],[89],[156],[266],[447],[141],[77],[159],[207],[86],[285],[276],[226],[223],[71],[258],[308],[190],[318],[265],[348],[240],[159],[291],[143],[129],[181],[312],[243],[358],[241],[226],[309],[113],[185],[204],[256],[380],[277],[324],[116],[272],[106],[199],[97],[152],[304],[176],[230],[237],[99],[105],[198],[181],[257],[195],[189],[241],[331],[154],[286],[230],[286],[177],[158],[354],[84],[184],[170],[406],[129],[327],[251],[233],[315],[187],[193],[165],[217],[246],[189],[184],[295],[84],[307],[341],[96],[196],[161],[214],[345],[158],[284],[124],[200],[285],[178],[303],[100],[128],[268],[272],[382],[290],[191],[209],[253],[325],[298],[139],[260],[178],[171],[73],[103],[293],[206],[153],[210],[142],[186],[114],[118],[252],[219],[139],[214],[337],[88],[329],[196],[212],[269],[175],[201],[434],[332],[355],[287],[234],[75],[204],[277],[126],[225],[408],[217],[181],[206],[190],[291],[134],[327],[181],[246],[192],[174],[173],[163],[274],[212],[150],[134],[160],[179],[101],[250],[172],[272],[90],[189],[223],[354],[257],[335],[362],[165],[187],[345],[179],[296],[314],[170],[174],[291],[255],[311],[137],[167],[178],[255],[302],[311],[180],[250],[89],[63],[279],[205],[257],[281],[278],[179],[216],[216],[265],[195],[298],[295],[175],[266],[177],[232],[257],[275],[259],[197],[182],[220],[262],[235],[300],[148],[158],[338],[160],[267],[227],[325],[311],[189],[203],[355],[319],[225],[168],[102],[172],[246],[135],[248],[296],[301],[383],[186],[239],[129],[110],[188],[170],[308],[284],[93],[187],[95],[286],[344],[171],[126],[188],[436],[138],[241],[209],[177],[287],[194],[185],[191],[189],[320],[198],[136],[310],[221],[200],[251],[228],[198],[273],[330],[296],[185],[176],[313],[147],[296],[133],[186],[274],[246],[193],[185],[226],[266],[242],[240],[96],[284],[296],[191],[161],[149],[309],[65],[152],[200],[154],[103],[186],[185],[170],[193],[315],[154],[134],[253],[222],[254],[151],[190],[187],[226],[185],[163],[164],[246],[158],[267],[106],[122],[233],[270],[301],[359],[187],[268],[172],[171],[233],[223],[377],[250],[181],[65],[119],[225],[293],[182],[406],[226],[195],[79],[85],[325],[180],[248],[294],[225],[141],[228],[239],[196],[205],[360],[123],[255],[96],[134],[161],[122],[198],[287],[186],[183],[272],[372],[78],[224],[151],[232],[157],[98],[177],[157],[140],[174],[182],[242],[87],[346],[171],[202],[185],[232],[183],[162],[334],[241],[309],[185],[167],[143],[183],[228],[218],[197],[287],[263],[167],[333],[238],[276],[133],[320],[290],[125],[136],[133],[259],[149],[330],[170],[334],[293],[181],[88],[183],[323],[282],[343],[89],[181],[171],[226],[232],[195],[261],[109],[223],[311],[279],[200],[226],[153],[171],[176],[319],[308],[172],[142],[294],[156],[166],[91],[259],[348],[175],[194],[71],[324],[217],[188],[221],[206],[165],[203],[137],[182],[184],[368],[163],[189],[385],[326],[290],[260],[199],[357],[187],[408],[198],[197],[190],[312],[239],[207],[200],[209],[238],[256],[166],[178],[167],[160],[310],[108],[140],[291],[308],[176],[176],[219],[229],[163],[286],[199],[134],[136],[159],[166],[362],[180],[169],[301],[212],[168],[274],[123],[167],[156],[234],[262],[235],[213],[175],[189],[315],[215],[250],[223],[232],[84],[241],[233],[109],[212],[286],[89],[165],[208],[192],[160],[194],[174],[222],[171],[204],[149],[219],[191],[319],[282],[94],[244],[181],[344],[182],[189],[180],[193],[315],[169],[177],[235],[159],[269],[217],[201],[146],[110],[192],[290],[82],[101],[237],[213],[189],[345],[143],[167],[97],[335],[260],[71],[177],[168],[208],[252],[194],[243],[188],[237],[197],[156],[245],[169],[286],[246],[287],[201],[198],[151],[66],[162],[270],[163],[152],[183],[167],[377],[100],[167],[225],[207],[248],[218],[152],[148],[292],[173],[182],[122],[179],[141],[100],[70],[60],[314],[243],[207],[193],[266],[195],[268],[248],[227],[304],[180],[179],[257],[248],[291],[111],[153],[195],[168],[252],[285],[178],[93],[245],[318],[244],[178],[152],[261],[117],[155],[200],[170],[276],[69],[176],[296],[280],[168],[245],[275],[207],[283],[211],[268],[209],[149],[209],[184],[225],[107],[169],[83],[258],[198],[208],[220],[186],[178],[193],[175],[181],[202],[80],[200],[325],[330],[191],[194],[176],[173],[194],[224],[163],[212],[92],[176],[190],[175],[95],[181],[60],[98],[175],[167],[162],[148],[176],[222],[189],[212],[189],[82],[265],[208],[195],[93],[206],[248],[322],[370],[92],[152],[191],[220],[236],[275],[218],[268],[315],[226],[273],[242],[222],[352],[165],[325],[331],[186],[107],[213],[178],[201],[163],[258],[169],[189],[172],[230],[230],[168],[191],[233],[228],[89],[156],[177],[339],[164],[173],[201],[166],[174],[231],[264],[128],[191],[218],[357],[315],[168],[249],[194],[165],[153],[197],[198],[193],[121],[141],[376],[215],[216],[145],[147],[198],[94],[148],[150],[205],[90],[175],[316],[206],[289],[268],[154],[163],[167],[268],[239],[168],[256],[251],[285],[162],[182],[168],[129],[192],[329],[174],[236],[92],[310],[178],[183],[231],[295],[326],[286],[195],[201],[268],[128],[202],[158],[151],[201],[287],[504],[270],[211],[313],[161],[177],[89],[145],[221],[69],[241],[82],[262],[213],[307],[93],[191],[260],[351],[83],[348],[191],[247],[97],[317],[303],[184],[113],[192],[195],[177],[84],[167],[194],[152],[179],[180],[259],[196],[184],[188],[304],[99],[61],[237],[355],[274],[181],[129],[60],[198],[322],[306],[312],[230],[232],[273],[282],[161],[300],[359],[161],[165],[129],[248],[368],[186],[60],[230],[327],[236],[335],[311],[107],[203],[138],[104],[195],[235],[76],[158],[110],[252],[333],[205],[241],[173],[156],[169],[207],[207],[159],[299],[101],[135],[300],[186],[314],[175],[172],[242],[350],[168],[311],[228],[286],[159],[221],[338],[192],[294],[177],[175],[269],[174],[154],[127],[100],[187],[187],[226],[199],[178],[262],[381],[322],[273],[326],[277],[90],[164],[202],[159],[188],[347],[171],[91],[91],[182],[218],[319],[187],[113],[133],[299],[195],[190],[237],[274],[157],[167],[176],[208],[158],[143],[324],[576],[250],[275],[286],[120],[163],[210],[233],[354],[206],[193],[307],[191],[123],[307],[212],[237],[309],[197],[231],[174],[197],[99],[108],[157],[214],[203],[268],[200],[96],[70],[138],[180],[187],[290],[147],[144],[189],[203],[192],[294],[266],[223],[227],[229],[267],[166],[203],[195],[237],[207],[283],[120],[159],[286],[94],[151],[161],[331],[138],[264],[175],[308],[112],[321],[205],[320],[98],[183],[314],[213],[228],[209],[145],[216],[274],[192],[271],[400],[205],[160],[319],[124],[196],[198],[180],[322],[85],[253],[230],[224],[173],[267],[242],[191],[199],[170],[156],[299],[278],[162],[247],[172],[220],[181],[220],[209],[296],[260],[287],[240],[260],[98],[129],[118],[172],[154],[272],[341],[169],[258],[168],[249],[235],[200],[268],[84],[140],[162],[343],[161],[142],[191],[322],[148],[224],[267],[189],[118],[159],[187],[170],[79],[265],[276],[269],[256],[126],[359],[212],[161],[156],[164]] 2 | -------------------------------------------------------------------------------- /data/barley.json: -------------------------------------------------------------------------------- 1 | [{"yield":27,"variety":"Manchuria","year":1931,"site":"University Farm"}, 2 | {"yield":48.86667,"variety":"Manchuria","year":1931,"site":"Waseca"}, 3 | {"yield":27.43334,"variety":"Manchuria","year":1931,"site":"Morris"}, 4 | {"yield":39.93333,"variety":"Manchuria","year":1931,"site":"Crookston"}, 5 | {"yield":32.96667,"variety":"Manchuria","year":1931,"site":"Grand Rapids"}, 6 | {"yield":28.96667,"variety":"Manchuria","year":1931,"site":"Duluth"}, 7 | {"yield":43.06666,"variety":"Glabron","year":1931,"site":"University Farm"}, 8 | {"yield":55.2,"variety":"Glabron","year":1931,"site":"Waseca"}, 9 | {"yield":28.76667,"variety":"Glabron","year":1931,"site":"Morris"}, 10 | {"yield":38.13333,"variety":"Glabron","year":1931,"site":"Crookston"}, 11 | {"yield":29.13333,"variety":"Glabron","year":1931,"site":"Grand Rapids"}, 12 | {"yield":29.66667,"variety":"Glabron","year":1931,"site":"Duluth"}, 13 | {"yield":35.13333,"variety":"Svansota","year":1931,"site":"University Farm"}, 14 | {"yield":47.33333,"variety":"Svansota","year":1931,"site":"Waseca"}, 15 | {"yield":25.76667,"variety":"Svansota","year":1931,"site":"Morris"}, 16 | {"yield":40.46667,"variety":"Svansota","year":1931,"site":"Crookston"}, 17 | {"yield":29.66667,"variety":"Svansota","year":1931,"site":"Grand Rapids"}, 18 | {"yield":25.7,"variety":"Svansota","year":1931,"site":"Duluth"}, 19 | {"yield":39.9,"variety":"Velvet","year":1931,"site":"University Farm"}, 20 | {"yield":50.23333,"variety":"Velvet","year":1931,"site":"Waseca"}, 21 | {"yield":26.13333,"variety":"Velvet","year":1931,"site":"Morris"}, 22 | {"yield":41.33333,"variety":"Velvet","year":1931,"site":"Crookston"}, 23 | {"yield":23.03333,"variety":"Velvet","year":1931,"site":"Grand Rapids"}, 24 | {"yield":26.3,"variety":"Velvet","year":1931,"site":"Duluth"}, 25 | {"yield":36.56666,"variety":"Trebi","year":1931,"site":"University Farm"}, 26 | {"yield":63.8333,"variety":"Trebi","year":1931,"site":"Waseca"}, 27 | {"yield":43.76667,"variety":"Trebi","year":1931,"site":"Morris"}, 28 | {"yield":46.93333,"variety":"Trebi","year":1931,"site":"Crookston"}, 29 | {"yield":29.76667,"variety":"Trebi","year":1931,"site":"Grand Rapids"}, 30 | {"yield":33.93333,"variety":"Trebi","year":1931,"site":"Duluth"}, 31 | {"yield":43.26667,"variety":"No. 457","year":1931,"site":"University Farm"}, 32 | {"yield":58.1,"variety":"No. 457","year":1931,"site":"Waseca"}, 33 | {"yield":28.7,"variety":"No. 457","year":1931,"site":"Morris"}, 34 | {"yield":45.66667,"variety":"No. 457","year":1931,"site":"Crookston"}, 35 | {"yield":32.16667,"variety":"No. 457","year":1931,"site":"Grand Rapids"}, 36 | {"yield":33.6,"variety":"No. 457","year":1931,"site":"Duluth"}, 37 | {"yield":36.6,"variety":"No. 462","year":1931,"site":"University Farm"}, 38 | {"yield":65.7667,"variety":"No. 462","year":1931,"site":"Waseca"}, 39 | {"yield":30.36667,"variety":"No. 462","year":1931,"site":"Morris"}, 40 | {"yield":48.56666,"variety":"No. 462","year":1931,"site":"Crookston"}, 41 | {"yield":24.93334,"variety":"No. 462","year":1931,"site":"Grand Rapids"}, 42 | {"yield":28.1,"variety":"No. 462","year":1931,"site":"Duluth"}, 43 | {"yield":32.76667,"variety":"Peatland","year":1931,"site":"University Farm"}, 44 | {"yield":48.56666,"variety":"Peatland","year":1931,"site":"Waseca"}, 45 | {"yield":29.86667,"variety":"Peatland","year":1931,"site":"Morris"}, 46 | {"yield":41.6,"variety":"Peatland","year":1931,"site":"Crookston"}, 47 | {"yield":34.7,"variety":"Peatland","year":1931,"site":"Grand Rapids"}, 48 | {"yield":32,"variety":"Peatland","year":1931,"site":"Duluth"}, 49 | {"yield":24.66667,"variety":"No. 475","year":1931,"site":"University Farm"}, 50 | {"yield":46.76667,"variety":"No. 475","year":1931,"site":"Waseca"}, 51 | {"yield":22.6,"variety":"No. 475","year":1931,"site":"Morris"}, 52 | {"yield":44.1,"variety":"No. 475","year":1931,"site":"Crookston"}, 53 | {"yield":19.7,"variety":"No. 475","year":1931,"site":"Grand Rapids"}, 54 | {"yield":33.06666,"variety":"No. 475","year":1931,"site":"Duluth"}, 55 | {"yield":39.3,"variety":"Wisconsin No. 38","year":1931,"site":"University Farm"}, 56 | {"yield":58.8,"variety":"Wisconsin No. 38","year":1931,"site":"Waseca"}, 57 | {"yield":29.46667,"variety":"Wisconsin No. 38","year":1931,"site":"Morris"}, 58 | {"yield":49.86667,"variety":"Wisconsin No. 38","year":1931,"site":"Crookston"}, 59 | {"yield":34.46667,"variety":"Wisconsin No. 38","year":1931,"site":"Grand Rapids"}, 60 | {"yield":31.6,"variety":"Wisconsin No. 38","year":1931,"site":"Duluth"}, 61 | {"yield":26.9,"variety":"Manchuria","year":1932,"site":"University Farm"}, 62 | {"yield":33.46667,"variety":"Manchuria","year":1932,"site":"Waseca"}, 63 | {"yield":34.36666,"variety":"Manchuria","year":1932,"site":"Morris"}, 64 | {"yield":32.96667,"variety":"Manchuria","year":1932,"site":"Crookston"}, 65 | {"yield":22.13333,"variety":"Manchuria","year":1932,"site":"Grand Rapids"}, 66 | {"yield":22.56667,"variety":"Manchuria","year":1932,"site":"Duluth"}, 67 | {"yield":36.8,"variety":"Glabron","year":1932,"site":"University Farm"}, 68 | {"yield":37.73333,"variety":"Glabron","year":1932,"site":"Waseca"}, 69 | {"yield":35.13333,"variety":"Glabron","year":1932,"site":"Morris"}, 70 | {"yield":26.16667,"variety":"Glabron","year":1932,"site":"Crookston"}, 71 | {"yield":14.43333,"variety":"Glabron","year":1932,"site":"Grand Rapids"}, 72 | {"yield":25.86667,"variety":"Glabron","year":1932,"site":"Duluth"}, 73 | {"yield":27.43334,"variety":"Svansota","year":1932,"site":"University Farm"}, 74 | {"yield":38.5,"variety":"Svansota","year":1932,"site":"Waseca"}, 75 | {"yield":35.03333,"variety":"Svansota","year":1932,"site":"Morris"}, 76 | {"yield":20.63333,"variety":"Svansota","year":1932,"site":"Crookston"}, 77 | {"yield":16.63333,"variety":"Svansota","year":1932,"site":"Grand Rapids"}, 78 | {"yield":22.23333,"variety":"Svansota","year":1932,"site":"Duluth"}, 79 | {"yield":26.8,"variety":"Velvet","year":1932,"site":"University Farm"}, 80 | {"yield":37.4,"variety":"Velvet","year":1932,"site":"Waseca"}, 81 | {"yield":38.83333,"variety":"Velvet","year":1932,"site":"Morris"}, 82 | {"yield":32.06666,"variety":"Velvet","year":1932,"site":"Crookston"}, 83 | {"yield":32.23333,"variety":"Velvet","year":1932,"site":"Grand Rapids"}, 84 | {"yield":22.46667,"variety":"Velvet","year":1932,"site":"Duluth"}, 85 | {"yield":29.06667,"variety":"Trebi","year":1932,"site":"University Farm"}, 86 | {"yield":49.2333,"variety":"Trebi","year":1932,"site":"Waseca"}, 87 | {"yield":46.63333,"variety":"Trebi","year":1932,"site":"Morris"}, 88 | {"yield":41.83333,"variety":"Trebi","year":1932,"site":"Crookston"}, 89 | {"yield":20.63333,"variety":"Trebi","year":1932,"site":"Grand Rapids"}, 90 | {"yield":30.6,"variety":"Trebi","year":1932,"site":"Duluth"}, 91 | {"yield":26.43334,"variety":"No. 457","year":1932,"site":"University Farm"}, 92 | {"yield":42.2,"variety":"No. 457","year":1932,"site":"Waseca"}, 93 | {"yield":43.53334,"variety":"No. 457","year":1932,"site":"Morris"}, 94 | {"yield":34.33333,"variety":"No. 457","year":1932,"site":"Crookston"}, 95 | {"yield":19.46667,"variety":"No. 457","year":1932,"site":"Grand Rapids"}, 96 | {"yield":22.7,"variety":"No. 457","year":1932,"site":"Duluth"}, 97 | {"yield":25.56667,"variety":"No. 462","year":1932,"site":"University Farm"}, 98 | {"yield":44.7,"variety":"No. 462","year":1932,"site":"Waseca"}, 99 | {"yield":47,"variety":"No. 462","year":1932,"site":"Morris"}, 100 | {"yield":30.53333,"variety":"No. 462","year":1932,"site":"Crookston"}, 101 | {"yield":19.9,"variety":"No. 462","year":1932,"site":"Grand Rapids"}, 102 | {"yield":22.5,"variety":"No. 462","year":1932,"site":"Duluth"}, 103 | {"yield":28.06667,"variety":"Peatland","year":1932,"site":"University Farm"}, 104 | {"yield":36.03333,"variety":"Peatland","year":1932,"site":"Waseca"}, 105 | {"yield":43.2,"variety":"Peatland","year":1932,"site":"Morris"}, 106 | {"yield":25.23333,"variety":"Peatland","year":1932,"site":"Crookston"}, 107 | {"yield":26.76667,"variety":"Peatland","year":1932,"site":"Grand Rapids"}, 108 | {"yield":31.36667,"variety":"Peatland","year":1932,"site":"Duluth"}, 109 | {"yield":30,"variety":"No. 475","year":1932,"site":"University Farm"}, 110 | {"yield":41.26667,"variety":"No. 475","year":1932,"site":"Waseca"}, 111 | {"yield":44.23333,"variety":"No. 475","year":1932,"site":"Morris"}, 112 | {"yield":32.13333,"variety":"No. 475","year":1932,"site":"Crookston"}, 113 | {"yield":15.23333,"variety":"No. 475","year":1932,"site":"Grand Rapids"}, 114 | {"yield":27.36667,"variety":"No. 475","year":1932,"site":"Duluth"}, 115 | {"yield":38,"variety":"Wisconsin No. 38","year":1932,"site":"University Farm"}, 116 | {"yield":58.16667,"variety":"Wisconsin No. 38","year":1932,"site":"Waseca"}, 117 | {"yield":47.16667,"variety":"Wisconsin No. 38","year":1932,"site":"Morris"}, 118 | {"yield":35.9,"variety":"Wisconsin No. 38","year":1932,"site":"Crookston"}, 119 | {"yield":20.66667,"variety":"Wisconsin No. 38","year":1932,"site":"Grand Rapids"}, 120 | {"yield":29.33333,"variety":"Wisconsin No. 38","year":1932,"site":"Duluth"}] -------------------------------------------------------------------------------- /data/driving.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"side": "left", "year": 1956, "miles": 3675, "gas": 2.38}, 3 | {"side": "right", "year": 1957, "miles": 3706, "gas": 2.40}, 4 | {"side": "bottom", "year": 1958, "miles": 3766, "gas": 2.26}, 5 | {"side": "top", "year": 1959, "miles": 3905, "gas": 2.31}, 6 | {"side": "right", "year": 1960, "miles": 3935, "gas": 2.27}, 7 | {"side": "bottom", "year": 1961, "miles": 3977, "gas": 2.25}, 8 | {"side": "right", "year": 1962, "miles": 4085, "gas": 2.22}, 9 | {"side": "bottom", "year": 1963, "miles": 4218, "gas": 2.12}, 10 | {"side": "bottom", "year": 1964, "miles": 4369, "gas": 2.11}, 11 | {"side": "bottom", "year": 1965, "miles": 4538, "gas": 2.14}, 12 | {"side": "top", "year": 1966, "miles": 4676, "gas": 2.14}, 13 | {"side": "bottom", "year": 1967, "miles": 4827, "gas": 2.14}, 14 | {"side": "right", "year": 1968, "miles": 5038, "gas": 2.13}, 15 | {"side": "right", "year": 1969, "miles": 5207, "gas": 2.07}, 16 | {"side": "right", "year": 1970, "miles": 5376, "gas": 2.01}, 17 | {"side": "bottom", "year": 1971, "miles": 5617, "gas": 1.93}, 18 | {"side": "bottom", "year": 1972, "miles": 5973, "gas": 1.87}, 19 | {"side": "right", "year": 1973, "miles": 6154, "gas": 1.90}, 20 | {"side": "left", "year": 1974, "miles": 5943, "gas": 2.34}, 21 | {"side": "bottom", "year": 1975, "miles": 6111, "gas": 2.31}, 22 | {"side": "bottom", "year": 1976, "miles": 6389, "gas": 2.32}, 23 | {"side": "top", "year": 1977, "miles": 6630, "gas": 2.36}, 24 | {"side": "bottom", "year": 1978, "miles": 6883, "gas": 2.23}, 25 | {"side": "left", "year": 1979, "miles": 6744, "gas": 2.68}, 26 | {"side": "left", "year": 1980, "miles": 6672, "gas": 3.30}, 27 | {"side": "right", "year": 1981, "miles": 6732, "gas": 3.30}, 28 | {"side": "right", "year": 1982, "miles": 6835, "gas": 2.92}, 29 | {"side": "right", "year": 1983, "miles": 6943, "gas": 2.66}, 30 | {"side": "right", "year": 1984, "miles": 7130, "gas": 2.48}, 31 | {"side": "right", "year": 1985, "miles": 7323, "gas": 2.36}, 32 | {"side": "left", "year": 1986, "miles": 7558, "gas": 1.76}, 33 | {"side": "top", "year": 1987, "miles": 7770, "gas": 1.76}, 34 | {"side": "bottom", "year": 1988, "miles": 8089, "gas": 1.68}, 35 | {"side": "left", "year": 1989, "miles": 8397, "gas": 1.75}, 36 | {"side": "top", "year": 1990, "miles": 8529, "gas": 1.88}, 37 | {"side": "right", "year": 1991, "miles": 8535, "gas": 1.78}, 38 | {"side": "right", "year": 1992, "miles": 8662, "gas": 1.69}, 39 | {"side": "left", "year": 1993, "miles": 8855, "gas": 1.60}, 40 | {"side": "bottom", "year": 1994, "miles": 8909, "gas": 1.59}, 41 | {"side": "bottom", "year": 1995, "miles": 9150, "gas": 1.60}, 42 | {"side": "top", "year": 1996, "miles": 9192, "gas": 1.67}, 43 | {"side": "right", "year": 1997, "miles": 9416, "gas": 1.65}, 44 | {"side": "bottom", "year": 1998, "miles": 9590, "gas": 1.39}, 45 | {"side": "right", "year": 1999, "miles": 9687, "gas": 1.50}, 46 | {"side": "top", "year": 2000, "miles": 9717, "gas": 1.89}, 47 | {"side": "left", "year": 2001, "miles": 9699, "gas": 1.77}, 48 | {"side": "bottom", "year": 2002, "miles": 9814, "gas": 1.64}, 49 | {"side": "right", "year": 2003, "miles": 9868, "gas": 1.86}, 50 | {"side": "left", "year": 2004, "miles": 9994, "gas": 2.14}, 51 | {"side": "left", "year": 2005, "miles": 10067, "gas": 2.53}, 52 | {"side": "right", "year": 2006, "miles": 10037, "gas": 2.79}, 53 | {"side": "right", "year": 2007, "miles": 10025, "gas": 2.95}, 54 | {"side": "left", "year": 2008, "miles": 9880, "gas": 3.31}, 55 | {"side": "bottom", "year": 2009, "miles": 9657, "gas": 2.38}, 56 | {"side": "left", "year": 2010, "miles": 9596, "gas": 2.61} 57 | ] -------------------------------------------------------------------------------- /data/earthquake.json: -------------------------------------------------------------------------------- 1 | [{"Quake":"T","Richter":5,"distance":7.5,"soil":"R","accel":0.264},{"Quake":"T","Richter":5,"distance":8.8,"soil":"R","accel":0.263},{"Quake":"T","Richter":5,"distance":8.9,"soil":"R","accel":0.23},{"Quake":"T","Richter":5,"distance":9.4,"soil":"R","accel":0.147},{"Quake":"T","Richter":5,"distance":9.7,"soil":"R","accel":0.286},{"Quake":"T","Richter":5,"distance":9.7,"soil":"R","accel":0.157},{"Quake":"T","Richter":5,"distance":10.5,"soil":"R","accel":0.237},{"Quake":"T","Richter":5,"distance":10.5,"soil":"R","accel":0.133},{"Quake":"T","Richter":5,"distance":12,"soil":"R","accel":0.055},{"Quake":"T","Richter":5,"distance":12.2,"soil":"R","accel":0.097},{"Quake":"T","Richter":5,"distance":12.8,"soil":"R","accel":0.129},{"Quake":"T","Richter":5,"distance":14.6,"soil":"R","accel":0.192},{"Quake":"T","Richter":5,"distance":14.9,"soil":"R","accel":0.147},{"Quake":"T","Richter":5,"distance":17.6,"soil":"R","accel":0.154},{"Quake":"T","Richter":5,"distance":23.9,"soil":"R","accel":0.06},{"Quake":"T","Richter":5,"distance":25,"soil":"R","accel":0.057},{"Quake":"P","Richter":5.1,"distance":2.9,"soil":"R","accel":0.21},{"Quake":"P","Richter":5.1,"distance":3.2,"soil":"R","accel":0.39},{"Quake":"P","Richter":5.1,"distance":7.6,"soil":"R","accel":0.28},{"Quake":"N","Richter":5.2,"distance":17,"soil":"S","accel":0.011},{"Quake":"N","Richter":5.2,"distance":8,"soil":"R","accel":0.12},{"Quake":"N","Richter":5.2,"distance":10,"soil":"R","accel":0.17},{"Quake":"N","Richter":5.2,"distance":10,"soil":"R","accel":0.14},{"Quake":"C","Richter":5.3,"distance":8,"soil":"S","accel":0.127},{"Quake":"H","Richter":5.3,"distance":19,"soil":"S","accel":0.086},{"Quake":"H","Richter":5.3,"distance":21,"soil":"S","accel":0.179},{"Quake":"H","Richter":5.3,"distance":13,"soil":"R","accel":0.205},{"Quake":"H","Richter":5.3,"distance":22,"soil":"R","accel":0.073},{"Quake":"H","Richter":5.3,"distance":29,"soil":"R","accel":0.045},{"Quake":"J","Richter":5.3,"distance":31,"soil":"R","accel":0.03},{"Quake":"W","Richter":5.3,"distance":5.8,"soil":"R","accel":0.123},{"Quake":"W","Richter":5.3,"distance":12,"soil":"R","accel":0.133},{"Quake":"W","Richter":5.3,"distance":12.1,"soil":"R","accel":0.073},{"Quake":"W","Richter":5.3,"distance":20.5,"soil":"R","accel":0.097},{"Quake":"W","Richter":5.3,"distance":20.5,"soil":"R","accel":0.096},{"Quake":"W","Richter":5.3,"distance":25.3,"soil":"R","accel":0.23},{"Quake":"W","Richter":5.3,"distance":35.9,"soil":"R","accel":0.082},{"Quake":"W","Richter":5.3,"distance":36.1,"soil":"R","accel":0.11},{"Quake":"W","Richter":5.3,"distance":36.3,"soil":"R","accel":0.11},{"Quake":"W","Richter":5.3,"distance":38.5,"soil":"R","accel":0.094},{"Quake":"W","Richter":5.3,"distance":41.4,"soil":"R","accel":0.04},{"Quake":"W","Richter":5.3,"distance":43.6,"soil":"R","accel":0.05},{"Quake":"W","Richter":5.3,"distance":44.4,"soil":"R","accel":0.022},{"Quake":"W","Richter":5.3,"distance":46.1,"soil":"R","accel":0.07},{"Quake":"W","Richter":5.3,"distance":47.1,"soil":"R","accel":0.08},{"Quake":"W","Richter":5.3,"distance":47.7,"soil":"R","accel":0.033},{"Quake":"W","Richter":5.3,"distance":49.2,"soil":"R","accel":0.017},{"Quake":"W","Richter":5.3,"distance":53.1,"soil":"R","accel":0.022},{"Quake":"V","Richter":5.5,"distance":4,"soil":"R","accel":0.259},{"Quake":"V","Richter":5.5,"distance":10.1,"soil":"R","accel":0.267},{"Quake":"V","Richter":5.5,"distance":11.1,"soil":"R","accel":0.071},{"Quake":"V","Richter":5.5,"distance":17.7,"soil":"R","accel":0.275},{"Quake":"V","Richter":5.5,"distance":22.5,"soil":"R","accel":0.058},{"Quake":"V","Richter":5.5,"distance":26.5,"soil":"R","accel":0.026},{"Quake":"V","Richter":5.5,"distance":29,"soil":"R","accel":0.039},{"Quake":"V","Richter":5.5,"distance":30.9,"soil":"R","accel":0.112},{"Quake":"V","Richter":5.5,"distance":37.8,"soil":"R","accel":0.065},{"Quake":"V","Richter":5.5,"distance":48.3,"soil":"R","accel":0.026},{"Quake":"F","Richter":5.6,"distance":62,"soil":"R","accel":0.005},{"Quake":"M","Richter":5.6,"distance":50,"soil":"S","accel":0.031},{"Quake":"M","Richter":5.6,"distance":16,"soil":"R","accel":0.13},{"Quake":"G","Richter":5.7,"distance":62,"soil":"R","accel":0.003},{"Quake":"R","Richter":5.8,"distance":1.2,"soil":"S","accel":0.42},{"Quake":"R","Richter":5.8,"distance":1.6,"soil":"S","accel":0.23},{"Quake":"R","Richter":5.8,"distance":9.1,"soil":"S","accel":0.13},{"Quake":"R","Richter":5.8,"distance":3.7,"soil":"R","accel":0.26},{"Quake":"R","Richter":5.8,"distance":5.3,"soil":"R","accel":0.27},{"Quake":"R","Richter":5.8,"distance":7.4,"soil":"R","accel":0.26},{"Quake":"R","Richter":5.8,"distance":17.9,"soil":"R","accel":0.11},{"Quake":"R","Richter":5.8,"distance":19.2,"soil":"R","accel":0.12},{"Quake":"R","Richter":5.8,"distance":23.4,"soil":"R","accel":0.038},{"Quake":"R","Richter":5.8,"distance":30,"soil":"R","accel":0.044},{"Quake":"R","Richter":5.8,"distance":38.9,"soil":"R","accel":0.046},{"Quake":"U","Richter":5.8,"distance":10.8,"soil":"R","accel":0.12},{"Quake":"U","Richter":5.8,"distance":15.7,"soil":"R","accel":0.154},{"Quake":"U","Richter":5.8,"distance":16.7,"soil":"R","accel":0.052},{"Quake":"U","Richter":5.8,"distance":20.8,"soil":"R","accel":0.045},{"Quake":"U","Richter":5.8,"distance":28.5,"soil":"R","accel":0.086},{"Quake":"U","Richter":5.8,"distance":33.1,"soil":"R","accel":0.056},{"Quake":"U","Richter":5.8,"distance":40.3,"soil":"R","accel":0.065},{"Quake":"O","Richter":6,"distance":8,"soil":"S","accel":0.11},{"Quake":"O","Richter":6,"distance":32,"soil":"S","accel":0.04},{"Quake":"O","Richter":6,"distance":30,"soil":"R","accel":0.07},{"Quake":"O","Richter":6,"distance":31,"soil":"R","accel":0.08},{"Quake":"D","Richter":6.1,"distance":16.1,"soil":"S","accel":0.411},{"Quake":"D","Richter":6.1,"distance":63.6,"soil":"S","accel":0.018},{"Quake":"D","Richter":6.1,"distance":6.6,"soil":"R","accel":0.509},{"Quake":"D","Richter":6.1,"distance":9.3,"soil":"R","accel":0.467},{"Quake":"D","Richter":6.1,"distance":13,"soil":"R","accel":0.279},{"Quake":"D","Richter":6.1,"distance":17.3,"soil":"R","accel":0.072},{"Quake":"D","Richter":6.1,"distance":105,"soil":"R","accel":0.012},{"Quake":"D","Richter":6.1,"distance":112,"soil":"R","accel":0.006},{"Quake":"D","Richter":6.1,"distance":123,"soil":"R","accel":0.003},{"Quake":"L","Richter":6.2,"distance":5,"soil":"R","accel":0.39},{"Quake":"S","Richter":6.5,"distance":23.5,"soil":"S","accel":0.17},{"Quake":"S","Richter":6.5,"distance":26,"soil":"S","accel":0.21},{"Quake":"S","Richter":6.5,"distance":0.5,"soil":"R","accel":0.32},{"Quake":"S","Richter":6.5,"distance":0.6,"soil":"R","accel":0.52},{"Quake":"S","Richter":6.5,"distance":1.3,"soil":"R","accel":0.72},{"Quake":"S","Richter":6.5,"distance":1.4,"soil":"R","accel":0.32},{"Quake":"S","Richter":6.5,"distance":2.6,"soil":"R","accel":0.81},{"Quake":"S","Richter":6.5,"distance":3.8,"soil":"R","accel":0.64},{"Quake":"S","Richter":6.5,"distance":4,"soil":"R","accel":0.56},{"Quake":"S","Richter":6.5,"distance":5.1,"soil":"R","accel":0.51},{"Quake":"S","Richter":6.5,"distance":6.2,"soil":"R","accel":0.4},{"Quake":"S","Richter":6.5,"distance":6.8,"soil":"R","accel":0.61},{"Quake":"S","Richter":6.5,"distance":7.5,"soil":"R","accel":0.26},{"Quake":"S","Richter":6.5,"distance":7.6,"soil":"R","accel":0.24},{"Quake":"S","Richter":6.5,"distance":8.4,"soil":"R","accel":0.46},{"Quake":"S","Richter":6.5,"distance":8.5,"soil":"R","accel":0.22},{"Quake":"S","Richter":6.5,"distance":8.5,"soil":"R","accel":0.23},{"Quake":"S","Richter":6.5,"distance":10.6,"soil":"R","accel":0.28},{"Quake":"S","Richter":6.5,"distance":12.6,"soil":"R","accel":0.38},{"Quake":"S","Richter":6.5,"distance":12.7,"soil":"R","accel":0.27},{"Quake":"S","Richter":6.5,"distance":12.9,"soil":"R","accel":0.31},{"Quake":"S","Richter":6.5,"distance":14,"soil":"R","accel":0.2},{"Quake":"S","Richter":6.5,"distance":15,"soil":"R","accel":0.11},{"Quake":"S","Richter":6.5,"distance":16,"soil":"R","accel":0.43},{"Quake":"S","Richter":6.5,"distance":17.7,"soil":"R","accel":0.27},{"Quake":"S","Richter":6.5,"distance":18,"soil":"R","accel":0.15},{"Quake":"S","Richter":6.5,"distance":22,"soil":"R","accel":0.15},{"Quake":"S","Richter":6.5,"distance":22,"soil":"R","accel":0.15},{"Quake":"S","Richter":6.5,"distance":23,"soil":"R","accel":0.13},{"Quake":"S","Richter":6.5,"distance":23.2,"soil":"R","accel":0.19},{"Quake":"S","Richter":6.5,"distance":29,"soil":"R","accel":0.13},{"Quake":"S","Richter":6.5,"distance":32,"soil":"R","accel":0.066},{"Quake":"S","Richter":6.5,"distance":32.7,"soil":"R","accel":0.35},{"Quake":"S","Richter":6.5,"distance":36,"soil":"R","accel":0.1},{"Quake":"S","Richter":6.5,"distance":43.5,"soil":"R","accel":0.16},{"Quake":"S","Richter":6.5,"distance":49,"soil":"R","accel":0.14},{"Quake":"S","Richter":6.5,"distance":60,"soil":"R","accel":0.049},{"Quake":"S","Richter":6.5,"distance":64,"soil":"R","accel":0.034},{"Quake":"E","Richter":6.6,"distance":105,"soil":"S","accel":0.018},{"Quake":"E","Richter":6.6,"distance":122,"soil":"S","accel":0.048},{"Quake":"E","Richter":6.6,"distance":141,"soil":"S","accel":0.011},{"Quake":"E","Richter":6.6,"distance":200,"soil":"S","accel":0.007},{"Quake":"E","Richter":6.6,"distance":45,"soil":"R","accel":0.142},{"Quake":"E","Richter":6.6,"distance":130,"soil":"R","accel":0.031},{"Quake":"E","Richter":6.6,"distance":147,"soil":"R","accel":0.006},{"Quake":"E","Richter":6.6,"distance":187,"soil":"R","accel":0.01},{"Quake":"E","Richter":6.6,"distance":197,"soil":"R","accel":0.01},{"Quake":"E","Richter":6.6,"distance":203,"soil":"R","accel":0.006},{"Quake":"E","Richter":6.6,"distance":211,"soil":"R","accel":0.013},{"Quake":"I","Richter":6.6,"distance":17,"soil":"S","accel":0.374},{"Quake":"I","Richter":6.6,"distance":19.6,"soil":"S","accel":0.2},{"Quake":"I","Richter":6.6,"distance":20.2,"soil":"S","accel":0.147},{"Quake":"I","Richter":6.6,"distance":21.1,"soil":"S","accel":0.188},{"Quake":"I","Richter":6.6,"distance":21.9,"soil":"S","accel":0.204},{"Quake":"I","Richter":6.6,"distance":24.2,"soil":"S","accel":0.335},{"Quake":"I","Richter":6.6,"distance":66,"soil":"S","accel":0.057},{"Quake":"I","Richter":6.6,"distance":87,"soil":"S","accel":0.021},{"Quake":"I","Richter":6.6,"distance":23.4,"soil":"R","accel":0.152},{"Quake":"I","Richter":6.6,"distance":24.6,"soil":"R","accel":0.217},{"Quake":"I","Richter":6.6,"distance":25.7,"soil":"R","accel":0.114},{"Quake":"I","Richter":6.6,"distance":28.6,"soil":"R","accel":0.15},{"Quake":"I","Richter":6.6,"distance":37.4,"soil":"R","accel":0.148},{"Quake":"I","Richter":6.6,"distance":46.7,"soil":"R","accel":0.112},{"Quake":"I","Richter":6.6,"distance":56.9,"soil":"R","accel":0.043},{"Quake":"I","Richter":6.6,"distance":60.7,"soil":"R","accel":0.057},{"Quake":"I","Richter":6.6,"distance":61.4,"soil":"R","accel":0.03},{"Quake":"I","Richter":6.6,"distance":62,"soil":"R","accel":0.027},{"Quake":"I","Richter":6.6,"distance":64,"soil":"R","accel":0.028},{"Quake":"I","Richter":6.6,"distance":82,"soil":"R","accel":0.034},{"Quake":"I","Richter":6.6,"distance":88,"soil":"R","accel":0.03},{"Quake":"I","Richter":6.6,"distance":91,"soil":"R","accel":0.039},{"Quake":"A","Richter":7,"distance":12,"soil":"R","accel":0.359},{"Quake":"B","Richter":7.4,"distance":148,"soil":"S","accel":0.014},{"Quake":"B","Richter":7.4,"distance":42,"soil":"R","accel":0.196},{"Quake":"B","Richter":7.4,"distance":85,"soil":"R","accel":0.135},{"Quake":"B","Richter":7.4,"distance":107,"soil":"R","accel":0.062},{"Quake":"B","Richter":7.4,"distance":109,"soil":"R","accel":0.054},{"Quake":"B","Richter":7.4,"distance":156,"soil":"R","accel":0.014},{"Quake":"B","Richter":7.4,"distance":224,"soil":"R","accel":0.018},{"Quake":"B","Richter":7.4,"distance":293,"soil":"R","accel":0.01},{"Quake":"B","Richter":7.4,"distance":359,"soil":"R","accel":0.004},{"Quake":"B","Richter":7.4,"distance":370,"soil":"R","accel":0.004},{"Quake":"Q","Richter":7.6,"distance":25.4,"soil":"R","accel":0.16},{"Quake":"Q","Richter":7.6,"distance":32.9,"soil":"R","accel":0.064},{"Quake":"Q","Richter":7.6,"distance":92.2,"soil":"R","accel":0.09},{"Quake":"K","Richter":7.7,"distance":45,"soil":"S","accel":0.11},{"Quake":"K","Richter":7.7,"distance":145,"soil":"S","accel":0.01},{"Quake":"K","Richter":7.7,"distance":300,"soil":"R","accel":0.01}] 2 | -------------------------------------------------------------------------------- /data/faithful.json: -------------------------------------------------------------------------------- 1 | [{"eruptions":3.6,"waiting":79},{"eruptions":1.8,"waiting":54},{"eruptions":3.333,"waiting":74},{"eruptions":2.283,"waiting":62},{"eruptions":4.533,"waiting":85},{"eruptions":2.883,"waiting":55},{"eruptions":4.7,"waiting":88},{"eruptions":3.6,"waiting":85},{"eruptions":1.95,"waiting":51},{"eruptions":4.35,"waiting":85},{"eruptions":1.833,"waiting":54},{"eruptions":3.917,"waiting":84},{"eruptions":4.2,"waiting":78},{"eruptions":1.75,"waiting":47},{"eruptions":4.7,"waiting":83},{"eruptions":2.167,"waiting":52},{"eruptions":1.75,"waiting":62},{"eruptions":4.8,"waiting":84},{"eruptions":1.6,"waiting":52},{"eruptions":4.25,"waiting":79},{"eruptions":1.8,"waiting":51},{"eruptions":1.75,"waiting":47},{"eruptions":3.45,"waiting":78},{"eruptions":3.067,"waiting":69},{"eruptions":4.533,"waiting":74},{"eruptions":3.6,"waiting":83},{"eruptions":1.967,"waiting":55},{"eruptions":4.083,"waiting":76},{"eruptions":3.85,"waiting":78},{"eruptions":4.433,"waiting":79},{"eruptions":4.3,"waiting":73},{"eruptions":4.467,"waiting":77},{"eruptions":3.367,"waiting":66},{"eruptions":4.033,"waiting":80},{"eruptions":3.833,"waiting":74},{"eruptions":2.017,"waiting":52},{"eruptions":1.867,"waiting":48},{"eruptions":4.833,"waiting":80},{"eruptions":1.833,"waiting":59},{"eruptions":4.783,"waiting":90},{"eruptions":4.35,"waiting":80},{"eruptions":1.883,"waiting":58},{"eruptions":4.567,"waiting":84},{"eruptions":1.75,"waiting":58},{"eruptions":4.533,"waiting":73},{"eruptions":3.317,"waiting":83},{"eruptions":3.833,"waiting":64},{"eruptions":2.1,"waiting":53},{"eruptions":4.633,"waiting":82},{"eruptions":2,"waiting":59},{"eruptions":4.8,"waiting":75},{"eruptions":4.716,"waiting":90},{"eruptions":1.833,"waiting":54},{"eruptions":4.833,"waiting":80},{"eruptions":1.733,"waiting":54},{"eruptions":4.883,"waiting":83},{"eruptions":3.717,"waiting":71},{"eruptions":1.667,"waiting":64},{"eruptions":4.567,"waiting":77},{"eruptions":4.317,"waiting":81},{"eruptions":2.233,"waiting":59},{"eruptions":4.5,"waiting":84},{"eruptions":1.75,"waiting":48},{"eruptions":4.8,"waiting":82},{"eruptions":1.817,"waiting":60},{"eruptions":4.4,"waiting":92},{"eruptions":4.167,"waiting":78},{"eruptions":4.7,"waiting":78},{"eruptions":2.067,"waiting":65},{"eruptions":4.7,"waiting":73},{"eruptions":4.033,"waiting":82},{"eruptions":1.967,"waiting":56},{"eruptions":4.5,"waiting":79},{"eruptions":4,"waiting":71},{"eruptions":1.983,"waiting":62},{"eruptions":5.067,"waiting":76},{"eruptions":2.017,"waiting":60},{"eruptions":4.567,"waiting":78},{"eruptions":3.883,"waiting":76},{"eruptions":3.6,"waiting":83},{"eruptions":4.133,"waiting":75},{"eruptions":4.333,"waiting":82},{"eruptions":4.1,"waiting":70},{"eruptions":2.633,"waiting":65},{"eruptions":4.067,"waiting":73},{"eruptions":4.933,"waiting":88},{"eruptions":3.95,"waiting":76},{"eruptions":4.517,"waiting":80},{"eruptions":2.167,"waiting":48},{"eruptions":4,"waiting":86},{"eruptions":2.2,"waiting":60},{"eruptions":4.333,"waiting":90},{"eruptions":1.867,"waiting":50},{"eruptions":4.817,"waiting":78},{"eruptions":1.833,"waiting":63},{"eruptions":4.3,"waiting":72},{"eruptions":4.667,"waiting":84},{"eruptions":3.75,"waiting":75},{"eruptions":1.867,"waiting":51},{"eruptions":4.9,"waiting":82},{"eruptions":2.483,"waiting":62},{"eruptions":4.367,"waiting":88},{"eruptions":2.1,"waiting":49},{"eruptions":4.5,"waiting":83},{"eruptions":4.05,"waiting":81},{"eruptions":1.867,"waiting":47},{"eruptions":4.7,"waiting":84},{"eruptions":1.783,"waiting":52},{"eruptions":4.85,"waiting":86},{"eruptions":3.683,"waiting":81},{"eruptions":4.733,"waiting":75},{"eruptions":2.3,"waiting":59},{"eruptions":4.9,"waiting":89},{"eruptions":4.417,"waiting":79},{"eruptions":1.7,"waiting":59},{"eruptions":4.633,"waiting":81},{"eruptions":2.317,"waiting":50},{"eruptions":4.6,"waiting":85},{"eruptions":1.817,"waiting":59},{"eruptions":4.417,"waiting":87},{"eruptions":2.617,"waiting":53},{"eruptions":4.067,"waiting":69},{"eruptions":4.25,"waiting":77},{"eruptions":1.967,"waiting":56},{"eruptions":4.6,"waiting":88},{"eruptions":3.767,"waiting":81},{"eruptions":1.917,"waiting":45},{"eruptions":4.5,"waiting":82},{"eruptions":2.267,"waiting":55},{"eruptions":4.65,"waiting":90},{"eruptions":1.867,"waiting":45},{"eruptions":4.167,"waiting":83},{"eruptions":2.8,"waiting":56},{"eruptions":4.333,"waiting":89},{"eruptions":1.833,"waiting":46},{"eruptions":4.383,"waiting":82},{"eruptions":1.883,"waiting":51},{"eruptions":4.933,"waiting":86},{"eruptions":2.033,"waiting":53},{"eruptions":3.733,"waiting":79},{"eruptions":4.233,"waiting":81},{"eruptions":2.233,"waiting":60},{"eruptions":4.533,"waiting":82},{"eruptions":4.817,"waiting":77},{"eruptions":4.333,"waiting":76},{"eruptions":1.983,"waiting":59},{"eruptions":4.633,"waiting":80},{"eruptions":2.017,"waiting":49},{"eruptions":5.1,"waiting":96},{"eruptions":1.8,"waiting":53},{"eruptions":5.033,"waiting":77},{"eruptions":4,"waiting":77},{"eruptions":2.4,"waiting":65},{"eruptions":4.6,"waiting":81},{"eruptions":3.567,"waiting":71},{"eruptions":4,"waiting":70},{"eruptions":4.5,"waiting":81},{"eruptions":4.083,"waiting":93},{"eruptions":1.8,"waiting":53},{"eruptions":3.967,"waiting":89},{"eruptions":2.2,"waiting":45},{"eruptions":4.15,"waiting":86},{"eruptions":2,"waiting":58},{"eruptions":3.833,"waiting":78},{"eruptions":3.5,"waiting":66},{"eruptions":4.583,"waiting":76},{"eruptions":2.367,"waiting":63},{"eruptions":5,"waiting":88},{"eruptions":1.933,"waiting":52},{"eruptions":4.617,"waiting":93},{"eruptions":1.917,"waiting":49},{"eruptions":2.083,"waiting":57},{"eruptions":4.583,"waiting":77},{"eruptions":3.333,"waiting":68},{"eruptions":4.167,"waiting":81},{"eruptions":4.333,"waiting":81},{"eruptions":4.5,"waiting":73},{"eruptions":2.417,"waiting":50},{"eruptions":4,"waiting":85},{"eruptions":4.167,"waiting":74},{"eruptions":1.883,"waiting":55},{"eruptions":4.583,"waiting":77},{"eruptions":4.25,"waiting":83},{"eruptions":3.767,"waiting":83},{"eruptions":2.033,"waiting":51},{"eruptions":4.433,"waiting":78},{"eruptions":4.083,"waiting":84},{"eruptions":1.833,"waiting":46},{"eruptions":4.417,"waiting":83},{"eruptions":2.183,"waiting":55},{"eruptions":4.8,"waiting":81},{"eruptions":1.833,"waiting":57},{"eruptions":4.8,"waiting":76},{"eruptions":4.1,"waiting":84},{"eruptions":3.966,"waiting":77},{"eruptions":4.233,"waiting":81},{"eruptions":3.5,"waiting":87},{"eruptions":4.366,"waiting":77},{"eruptions":2.25,"waiting":51},{"eruptions":4.667,"waiting":78},{"eruptions":2.1,"waiting":60},{"eruptions":4.35,"waiting":82},{"eruptions":4.133,"waiting":91},{"eruptions":1.867,"waiting":53},{"eruptions":4.6,"waiting":78},{"eruptions":1.783,"waiting":46},{"eruptions":4.367,"waiting":77},{"eruptions":3.85,"waiting":84},{"eruptions":1.933,"waiting":49},{"eruptions":4.5,"waiting":83},{"eruptions":2.383,"waiting":71},{"eruptions":4.7,"waiting":80},{"eruptions":1.867,"waiting":49},{"eruptions":3.833,"waiting":75},{"eruptions":3.417,"waiting":64},{"eruptions":4.233,"waiting":76},{"eruptions":2.4,"waiting":53},{"eruptions":4.8,"waiting":94},{"eruptions":2,"waiting":55},{"eruptions":4.15,"waiting":76},{"eruptions":1.867,"waiting":50},{"eruptions":4.267,"waiting":82},{"eruptions":1.75,"waiting":54},{"eruptions":4.483,"waiting":75},{"eruptions":4,"waiting":78},{"eruptions":4.117,"waiting":79},{"eruptions":4.083,"waiting":78},{"eruptions":4.267,"waiting":78},{"eruptions":3.917,"waiting":70},{"eruptions":4.55,"waiting":79},{"eruptions":4.083,"waiting":70},{"eruptions":2.417,"waiting":54},{"eruptions":4.183,"waiting":86},{"eruptions":2.217,"waiting":50},{"eruptions":4.45,"waiting":90},{"eruptions":1.883,"waiting":54},{"eruptions":1.85,"waiting":54},{"eruptions":4.283,"waiting":77},{"eruptions":3.95,"waiting":79},{"eruptions":2.333,"waiting":64},{"eruptions":4.15,"waiting":75},{"eruptions":2.35,"waiting":47},{"eruptions":4.933,"waiting":86},{"eruptions":2.9,"waiting":63},{"eruptions":4.583,"waiting":85},{"eruptions":3.833,"waiting":82},{"eruptions":2.083,"waiting":57},{"eruptions":4.367,"waiting":82},{"eruptions":2.133,"waiting":67},{"eruptions":4.35,"waiting":74},{"eruptions":2.2,"waiting":54},{"eruptions":4.45,"waiting":83},{"eruptions":3.567,"waiting":73},{"eruptions":4.5,"waiting":73},{"eruptions":4.15,"waiting":88},{"eruptions":3.817,"waiting":80},{"eruptions":3.917,"waiting":71},{"eruptions":4.45,"waiting":83},{"eruptions":2,"waiting":56},{"eruptions":4.283,"waiting":79},{"eruptions":4.767,"waiting":78},{"eruptions":4.533,"waiting":84},{"eruptions":1.85,"waiting":58},{"eruptions":4.25,"waiting":83},{"eruptions":1.983,"waiting":43},{"eruptions":2.25,"waiting":60},{"eruptions":4.75,"waiting":75},{"eruptions":4.117,"waiting":81},{"eruptions":2.15,"waiting":46},{"eruptions":4.417,"waiting":90},{"eruptions":1.817,"waiting":46},{"eruptions":4.467,"waiting":74}] 2 | -------------------------------------------------------------------------------- /data/gapminder-health-income.csv: -------------------------------------------------------------------------------- 1 | country,income,health,population 2 | Afghanistan,1925,57.63,32526562 3 | Albania,10620,76,2896679 4 | Algeria,13434,76.5,39666519 5 | Andorra,46577,84.1,70473 6 | Angola,7615,61,25021974 7 | Antigua and Barbuda,21049,75.2,91818 8 | Argentina,17344,76.2,43416755 9 | Armenia,7763,74.4,3017712 10 | Australia,44056,81.8,23968973 11 | Austria,44401,81,8544586 12 | Azerbaijan,16986,72.9,9753968 13 | Bahamas,22818,72.3,388019 14 | Bahrain,44138,79.2,1377237 15 | Bangladesh,3161,70.1,160995642 16 | Barbados,12984,75.8,284215 17 | Belarus,17415,70.4,9495826 18 | Belgium,41240,80.4,11299192 19 | Belize,8501,70,359287 20 | Benin,1830,65.5,10879829 21 | Bhutan,7983,70.2,774830 22 | Bolivia,6295,72.3,10724705 23 | Bosnia and Herzegovina,9833,77.9,3810416 24 | Botswana,17196,66.4,2262485 25 | Brazil,15441,75.6,207847528 26 | Brunei,73003,78.7,423188 27 | Bulgaria,16371,74.9,7149787 28 | Burkina Faso,1654,62.8,18105570 29 | Burundi,777,60.4,11178921 30 | Cambodia,3267,68.4,15577899 31 | Cameroon,2897,59.5,23344179 32 | Canada,43294,81.7,35939927 33 | Cape Verde,6514,74.6,520502 34 | Central African Republic,599,53.8,4900274 35 | Chad,2191,57.7,14037472 36 | Chile,22465,79.3,17948141 37 | China,13334,76.9,1376048943 38 | Colombia,12761,75.8,48228704 39 | Comoros,1472,64.1,788474 40 | "Congo, Dem. Rep.",809,58.3,77266814 41 | "Congo, Rep.",6220,61.9,4620330 42 | Costa Rica,14132,80,4807850 43 | Cote d'Ivoire,3491,60.33,22701556 44 | Croatia,20260,78,4240317 45 | Cuba,21291,78.5,11389562 46 | Cyprus,29797,82.6,1165300 47 | Czech Republic,29437,78.6,10543186 48 | Denmark,43495,80.1,5669081 49 | Djibouti,3139,64.63,887861 50 | Dominica,10503,74.6,72680 51 | Dominican Republic,12837,73.8,10528391 52 | Ecuador,10996,75.2,16144363 53 | Egypt,11031,71.3,91508084 54 | El Salvador,7776,74.1,6126583 55 | Equatorial Guinea,31087,60.63,845060 56 | Eritrea,1129,62.9,5227791 57 | Estonia,26812,76.8,1312558 58 | Ethiopia,1520,63.6,99390750 59 | Fiji,7925,66.3,892145 60 | Finland,38923,80.8,5503457 61 | France,37599,81.9,64395345 62 | Gabon,18627,60.53,1725292 63 | Gambia,1644,65.1,1990924 64 | Georgia,7474,73.3,3999812 65 | Germany,44053,81.1,80688545 66 | Ghana,4099,65.5,27409893 67 | Greece,25430,79.8,10954617 68 | Grenada,11593,71.7,106825 69 | Guatemala,7279,73.1,16342897 70 | Guinea,1225,60.8,12608590 71 | Guinea-Bissau,1386,53.4,1844325 72 | Guyana,6816,64.4,767085 73 | Haiti,1710,65.3,10711067 74 | Honduras,4270,72.4,8075060 75 | Hungary,24200,76.2,9855023 76 | Iceland,42182,82.8,329425 77 | India,5903,66.8,1311050527 78 | Indonesia,10504,70.9,257563815 79 | Iran,15573,78.5,79109272 80 | Iraq,14646,72.1,36423395 81 | Ireland,47758,80.4,4688465 82 | Israel,31590,82.4,8064036 83 | Italy,33297,82.1,59797685 84 | Jamaica,8606,75.5,2793335 85 | Japan,36162,83.5,126573481 86 | Jordan,11752,78.3,7594547 87 | Kazakhstan,23468,68.2,17625226 88 | Kenya,2898,66.63,46050302 89 | Kiribati,1824,62.4,112423 90 | Kuwait,82633,80.7,3892115 91 | Kyrgyz Republic,3245,69,5939962 92 | Lao,5212,66.4,6802023 93 | Latvia,23282,75.7,1970503 94 | Lebanon,17050,78.5,5850743 95 | Lesotho,2598,48.5,2135022 96 | Liberia,958,63.9,4503438 97 | Libya,17261,76.2,6278438 98 | Lithuania,26665,75.4,2878405 99 | Luxembourg,88314,81.1,567110 100 | "Macedonia, FYR",12547,77,2078453 101 | Madagascar,1400,64.7,24235390 102 | Malawi,799,60.22,17215232 103 | Malaysia,24320,75.1,30331007 104 | Maldives,14408,79.5,363657 105 | Mali,1684,57.6,17599694 106 | Malta,30265,82.1,418670 107 | Marshall Islands,3661,65.1,52993 108 | Mauritania,3877,65.7,4067564 109 | Mauritius,18350,73.9,1273212 110 | Mexico,16850,74.5,127017224 111 | "Micronesia, Fed. Sts.",3510,67,104460 112 | Moldova,4896,72.7,4068897 113 | Mongolia,11819,65.3,2959134 114 | Montenegro,14833,75.8,625781 115 | Morocco,7319,74.7,34377511 116 | Mozambique,1176,56.4,27977863 117 | Myanmar,4012,67.9,53897154 118 | Namibia,10040,61,2458830 119 | Nepal,2352,71.2,28513700 120 | Netherlands,45784,80.6,16924929 121 | New Zealand,34186,80.6,4528526 122 | Nicaragua,4712,76.8,6082032 123 | Niger,943,62.2,19899120 124 | Nigeria,5727,61.33,182201962 125 | North Korea,1390,71.4,25155317 126 | Norway,64304,81.6,5210967 127 | Oman,48226,75.7,4490541 128 | Pakistan,4743,66.5,188924874 129 | Panama,20485,78.2,3929141 130 | Papua New Guinea,2529,60.6,7619321 131 | Paraguay,8219,73.9,6639123 132 | Peru,11903,77.5,31376670 133 | Philippines,6876,70.2,100699395 134 | Poland,24787,77.3,38611794 135 | Portugal,26437,79.8,10349803 136 | Qatar,132877,82,2235355 137 | Romania,19203,76.8,19511324 138 | Russia,23038,73.13,143456918 139 | Rwanda,1549,66.53,11609666 140 | Samoa,5558,72.2,193228 141 | Sao Tome and Principe,3003,68.8,190344 142 | Saudi Arabia,52469,78.1,31540372 143 | Senegal,2251,66.1,15129273 144 | Serbia,12908,78.1,8850975 145 | Seychelles,25684,73.7,96471 146 | Sierra Leone,2085,58.5,6453184 147 | Singapore,80794,82.1,5603740 148 | Slovak Republic,27204,76.4,5426258 149 | Slovenia,28550,80.2,2067526 150 | Solomon Islands,2047,64.1,583591 151 | Somalia,624,58.7,10787104 152 | South Africa,12509,63.72,54490406 153 | South Korea,34644,80.7,50293439 154 | South Sudan,3047,58,12339812 155 | Spain,32979,81.7,46121699 156 | Sri Lanka,10624,76.5,20715010 157 | St. Lucia,9997,74.5,184999 158 | St. Vincent and the Grenadines,10435,72.9,109462 159 | Sudan,3975,69.5,40234882 160 | Suriname,17125,70.5,542975 161 | Swaziland,6095,51.5,1286970 162 | Sweden,44892,82,9779426 163 | Switzerland,56118,82.9,8298663 164 | Syria,4637,70.26,18502413 165 | Tajikistan,2582,71,8481855 166 | Tanzania,2571,63.43,53470420 167 | Thailand,14512,75.1,67959359 168 | Timor-Leste,2086,72.4,1184765 169 | Togo,1433,64.23,7304578 170 | Tonga,5069,70.5,106170 171 | Trinidad and Tobago,30113,71.4,1360088 172 | Tunisia,11126,77.3,11253554 173 | Turkey,19360,76.5,78665830 174 | Turkmenistan,15865,67.9,5373502 175 | Uganda,1680,60.8,39032383 176 | Ukraine,8449,72.1,44823765 177 | United Arab Emirates,60749,76.6,9156963 178 | United Kingdom,38225,81.4,64715810 179 | United States,53354,79.1,321773631 180 | Uruguay,20438,77.3,3431555 181 | Uzbekistan,5598,70.1,29893488 182 | Vanuatu,2912,65,264652 183 | Venezuela,15753,75.8,31108083 184 | Vietnam,5623,76.5,93447601 185 | West Bank and Gaza,4319,75.2,4668466 186 | Yemen,3887,67.6,26832215 187 | Zambia,4034,58.96,16211767 188 | Zimbabwe,1801,60.01,15602751 189 | -------------------------------------------------------------------------------- /data/oats.json: -------------------------------------------------------------------------------- 1 | [{"Block":"I","Variety":"Victory","nitro":0,"yield":111},{"Block":"I","Variety":"Victory","nitro":0.2,"yield":130},{"Block":"I","Variety":"Victory","nitro":0.4,"yield":157},{"Block":"I","Variety":"Victory","nitro":0.6,"yield":174},{"Block":"I","Variety":"Golden Rain","nitro":0,"yield":117},{"Block":"I","Variety":"Golden Rain","nitro":0.2,"yield":114},{"Block":"I","Variety":"Golden Rain","nitro":0.4,"yield":161},{"Block":"I","Variety":"Golden Rain","nitro":0.6,"yield":141},{"Block":"I","Variety":"Marvellous","nitro":0,"yield":105},{"Block":"I","Variety":"Marvellous","nitro":0.2,"yield":140},{"Block":"I","Variety":"Marvellous","nitro":0.4,"yield":118},{"Block":"I","Variety":"Marvellous","nitro":0.6,"yield":156},{"Block":"II","Variety":"Victory","nitro":0,"yield":61},{"Block":"II","Variety":"Victory","nitro":0.2,"yield":91},{"Block":"II","Variety":"Victory","nitro":0.4,"yield":97},{"Block":"II","Variety":"Victory","nitro":0.6,"yield":100},{"Block":"II","Variety":"Golden Rain","nitro":0,"yield":70},{"Block":"II","Variety":"Golden Rain","nitro":0.2,"yield":108},{"Block":"II","Variety":"Golden Rain","nitro":0.4,"yield":126},{"Block":"II","Variety":"Golden Rain","nitro":0.6,"yield":149},{"Block":"II","Variety":"Marvellous","nitro":0,"yield":96},{"Block":"II","Variety":"Marvellous","nitro":0.2,"yield":124},{"Block":"II","Variety":"Marvellous","nitro":0.4,"yield":121},{"Block":"II","Variety":"Marvellous","nitro":0.6,"yield":144},{"Block":"III","Variety":"Victory","nitro":0,"yield":68},{"Block":"III","Variety":"Victory","nitro":0.2,"yield":64},{"Block":"III","Variety":"Victory","nitro":0.4,"yield":112},{"Block":"III","Variety":"Victory","nitro":0.6,"yield":86},{"Block":"III","Variety":"Golden Rain","nitro":0,"yield":60},{"Block":"III","Variety":"Golden Rain","nitro":0.2,"yield":102},{"Block":"III","Variety":"Golden Rain","nitro":0.4,"yield":89},{"Block":"III","Variety":"Golden Rain","nitro":0.6,"yield":96},{"Block":"III","Variety":"Marvellous","nitro":0,"yield":89},{"Block":"III","Variety":"Marvellous","nitro":0.2,"yield":129},{"Block":"III","Variety":"Marvellous","nitro":0.4,"yield":132},{"Block":"III","Variety":"Marvellous","nitro":0.6,"yield":124},{"Block":"IV","Variety":"Victory","nitro":0,"yield":74},{"Block":"IV","Variety":"Victory","nitro":0.2,"yield":89},{"Block":"IV","Variety":"Victory","nitro":0.4,"yield":81},{"Block":"IV","Variety":"Victory","nitro":0.6,"yield":122},{"Block":"IV","Variety":"Golden Rain","nitro":0,"yield":64},{"Block":"IV","Variety":"Golden Rain","nitro":0.2,"yield":103},{"Block":"IV","Variety":"Golden Rain","nitro":0.4,"yield":132},{"Block":"IV","Variety":"Golden Rain","nitro":0.6,"yield":133},{"Block":"IV","Variety":"Marvellous","nitro":0,"yield":70},{"Block":"IV","Variety":"Marvellous","nitro":0.2,"yield":89},{"Block":"IV","Variety":"Marvellous","nitro":0.4,"yield":104},{"Block":"IV","Variety":"Marvellous","nitro":0.6,"yield":117},{"Block":"V","Variety":"Victory","nitro":0,"yield":62},{"Block":"V","Variety":"Victory","nitro":0.2,"yield":90},{"Block":"V","Variety":"Victory","nitro":0.4,"yield":100},{"Block":"V","Variety":"Victory","nitro":0.6,"yield":116},{"Block":"V","Variety":"Golden Rain","nitro":0,"yield":80},{"Block":"V","Variety":"Golden Rain","nitro":0.2,"yield":82},{"Block":"V","Variety":"Golden Rain","nitro":0.4,"yield":94},{"Block":"V","Variety":"Golden Rain","nitro":0.6,"yield":126},{"Block":"V","Variety":"Marvellous","nitro":0,"yield":63},{"Block":"V","Variety":"Marvellous","nitro":0.2,"yield":70},{"Block":"V","Variety":"Marvellous","nitro":0.4,"yield":109},{"Block":"V","Variety":"Marvellous","nitro":0.6,"yield":99},{"Block":"VI","Variety":"Victory","nitro":0,"yield":53},{"Block":"VI","Variety":"Victory","nitro":0.2,"yield":74},{"Block":"VI","Variety":"Victory","nitro":0.4,"yield":118},{"Block":"VI","Variety":"Victory","nitro":0.6,"yield":113},{"Block":"VI","Variety":"Golden Rain","nitro":0,"yield":89},{"Block":"VI","Variety":"Golden Rain","nitro":0.2,"yield":82},{"Block":"VI","Variety":"Golden Rain","nitro":0.4,"yield":86},{"Block":"VI","Variety":"Golden Rain","nitro":0.6,"yield":104},{"Block":"VI","Variety":"Marvellous","nitro":0,"yield":97},{"Block":"VI","Variety":"Marvellous","nitro":0.2,"yield":99},{"Block":"VI","Variety":"Marvellous","nitro":0.4,"yield":119},{"Block":"VI","Variety":"Marvellous","nitro":0.6,"yield":121}] 2 | -------------------------------------------------------------------------------- /data/postdoc.json: -------------------------------------------------------------------------------- 1 | [{"Field":"Biological Sciences","Reason":"Expected or Additional Training","Freq":6404},{"Field":"Chemistry","Reason":"Expected or Additional Training","Freq":865},{"Field":"Earth, Atmospheric, and Ocean Sciences","Reason":"Expected or Additional Training","Freq":343},{"Field":"Engineering","Reason":"Expected or Additional Training","Freq":586},{"Field":"Medical Sciences","Reason":"Expected or Additional Training","Freq":205},{"Field":"Physics and Astronomy","Reason":"Expected or Additional Training","Freq":1010},{"Field":"Social and Behavioral Sciences","Reason":"Expected or Additional Training","Freq":1368},{"Field":"All Postdoctorates","Reason":"Expected or Additional Training","Freq":11197},{"Field":"Biological Sciences","Reason":"Work with Specific Person","Freq":2427},{"Field":"Chemistry","Reason":"Work with Specific Person","Freq":308},{"Field":"Earth, Atmospheric, and Ocean Sciences","Reason":"Work with Specific Person","Freq":75},{"Field":"Engineering","Reason":"Work with Specific Person","Freq":464},{"Field":"Medical Sciences","Reason":"Work with Specific Person","Freq":137},{"Field":"Physics and Astronomy","Reason":"Work with Specific Person","Freq":347},{"Field":"Social and Behavioral Sciences","Reason":"Work with Specific Person","Freq":564},{"Field":"All Postdoctorates","Reason":"Work with Specific Person","Freq":4687},{"Field":"Biological Sciences","Reason":"Training Outside PhD Field","Freq":1950},{"Field":"Chemistry","Reason":"Training Outside PhD Field","Freq":292},{"Field":"Earth, Atmospheric, and Ocean Sciences","Reason":"Training Outside PhD Field","Freq":75},{"Field":"Engineering","Reason":"Training Outside PhD Field","Freq":288},{"Field":"Medical Sciences","Reason":"Training Outside PhD Field","Freq":82},{"Field":"Physics and Astronomy","Reason":"Training Outside PhD Field","Freq":175},{"Field":"Social and Behavioral Sciences","Reason":"Training Outside PhD Field","Freq":412},{"Field":"All Postdoctorates","Reason":"Training Outside PhD Field","Freq":3403},{"Field":"Biological Sciences","Reason":"Other Employment Not Available","Freq":1779},{"Field":"Chemistry","Reason":"Other Employment Not Available","Freq":551},{"Field":"Earth, Atmospheric, and Ocean Sciences","Reason":"Other Employment Not Available","Freq":238},{"Field":"Engineering","Reason":"Other Employment Not Available","Freq":517},{"Field":"Medical Sciences","Reason":"Other Employment Not Available","Freq":68},{"Field":"Physics and Astronomy","Reason":"Other Employment Not Available","Freq":399},{"Field":"Social and Behavioral Sciences","Reason":"Other Employment Not Available","Freq":514},{"Field":"All Postdoctorates","Reason":"Other Employment Not Available","Freq":4406},{"Field":"Biological Sciences","Reason":"Other","Freq":602},{"Field":"Chemistry","Reason":"Other","Freq":168},{"Field":"Earth, Atmospheric, and Ocean Sciences","Reason":"Other","Freq":80},{"Field":"Engineering","Reason":"Other","Freq":401},{"Field":"Medical Sciences","Reason":"Other","Freq":74},{"Field":"Physics and Astronomy","Reason":"Other","Freq":162},{"Field":"Social and Behavioral Sciences","Reason":"Other","Freq":305},{"Field":"All Postdoctorates","Reason":"Other","Freq":1914}] 2 | -------------------------------------------------------------------------------- /data/sunspot_year.json: -------------------------------------------------------------------------------- 1 | [{"x":5},{"x":11},{"x":16},{"x":23},{"x":36},{"x":58},{"x":29},{"x":20},{"x":10},{"x":8},{"x":3},{"x":0},{"x":0},{"x":2},{"x":11},{"x":27},{"x":47},{"x":63},{"x":60},{"x":39},{"x":28},{"x":26},{"x":22},{"x":11},{"x":21},{"x":40},{"x":78},{"x":122},{"x":103},{"x":73},{"x":47},{"x":35},{"x":11},{"x":5},{"x":16},{"x":34},{"x":70},{"x":81},{"x":111},{"x":101},{"x":73},{"x":40},{"x":20},{"x":16},{"x":5},{"x":11},{"x":22},{"x":40},{"x":60},{"x":80.9},{"x":83.4},{"x":47.7},{"x":47.8},{"x":30.7},{"x":12.2},{"x":9.6},{"x":10.2},{"x":32.4},{"x":47.6},{"x":54},{"x":62.9},{"x":85.9},{"x":61.2},{"x":45.1},{"x":36.4},{"x":20.9},{"x":11.4},{"x":37.8},{"x":69.8},{"x":106.1},{"x":100.8},{"x":81.6},{"x":66.5},{"x":34.8},{"x":30.6},{"x":7},{"x":19.8},{"x":92.5},{"x":154.4},{"x":125.9},{"x":84.8},{"x":68.1},{"x":38.5},{"x":22.8},{"x":10.2},{"x":24.1},{"x":82.9},{"x":132},{"x":130.9},{"x":118.1},{"x":89.9},{"x":66.6},{"x":60},{"x":46.9},{"x":41},{"x":21.3},{"x":16},{"x":6.4},{"x":4.1},{"x":6.8},{"x":14.5},{"x":34},{"x":45},{"x":43.1},{"x":47.5},{"x":42.2},{"x":28.1},{"x":10.1},{"x":8.1},{"x":2.5},{"x":0},{"x":1.4},{"x":5},{"x":12.2},{"x":13.9},{"x":35.4},{"x":45.8},{"x":41.1},{"x":30.1},{"x":23.9},{"x":15.6},{"x":6.6},{"x":4},{"x":1.8},{"x":8.5},{"x":16.6},{"x":36.3},{"x":49.6},{"x":64.2},{"x":67},{"x":70.9},{"x":47.8},{"x":27.5},{"x":8.5},{"x":13.2},{"x":56.9},{"x":121.5},{"x":138.3},{"x":103.2},{"x":85.7},{"x":64.6},{"x":36.7},{"x":24.2},{"x":10.7},{"x":15},{"x":40.1},{"x":61.5},{"x":98.5},{"x":124.7},{"x":96.3},{"x":66.6},{"x":64.5},{"x":54.1},{"x":39},{"x":20.6},{"x":6.7},{"x":4.3},{"x":22.7},{"x":54.8},{"x":93.8},{"x":95.8},{"x":77.2},{"x":59.1},{"x":44},{"x":47},{"x":30.5},{"x":16.3},{"x":7.3},{"x":37.6},{"x":74},{"x":139},{"x":111.2},{"x":101.6},{"x":66.2},{"x":44.7},{"x":17},{"x":11.3},{"x":12.4},{"x":3.4},{"x":6},{"x":32.3},{"x":54.3},{"x":59.7},{"x":63.7},{"x":63.5},{"x":52.2},{"x":25.4},{"x":13.1},{"x":6.8},{"x":6.3},{"x":7.1},{"x":35.6},{"x":73},{"x":85.1},{"x":78},{"x":64},{"x":41.8},{"x":26.2},{"x":26.7},{"x":12.1},{"x":9.5},{"x":2.7},{"x":5},{"x":24.4},{"x":42},{"x":63.5},{"x":53.8},{"x":62},{"x":48.5},{"x":43.9},{"x":18.6},{"x":5.7},{"x":3.6},{"x":1.4},{"x":9.6},{"x":47.4},{"x":57.1},{"x":103.9},{"x":80.6},{"x":63.6},{"x":37.6},{"x":26.1},{"x":14.2},{"x":5.8},{"x":16.7},{"x":44.3},{"x":63.9},{"x":69},{"x":77.8},{"x":64.9},{"x":35.7},{"x":21.2},{"x":11.1},{"x":5.7},{"x":8.7},{"x":36.1},{"x":79.7},{"x":114.4},{"x":109.6},{"x":88.8},{"x":67.8},{"x":47.5},{"x":30.6},{"x":16.3},{"x":9.6},{"x":33.2},{"x":92.6},{"x":151.6},{"x":136.3},{"x":134.7},{"x":83.9},{"x":69.4},{"x":31.5},{"x":13.9},{"x":4.4},{"x":38},{"x":141.7},{"x":190.2},{"x":184.8},{"x":159},{"x":112.3},{"x":53.9},{"x":37.5},{"x":27.9},{"x":10.2},{"x":15.1},{"x":47},{"x":93.8},{"x":105.9},{"x":105.5},{"x":104.5},{"x":66.6},{"x":68.9},{"x":38},{"x":34.5},{"x":15.5},{"x":12.6},{"x":27.5},{"x":92.5},{"x":155.4},{"x":154.7},{"x":140.5},{"x":115.9},{"x":66.6},{"x":45.9},{"x":17.9},{"x":13.4},{"x":29.2},{"x":100.2}] 2 | -------------------------------------------------------------------------------- /data/titanic.json: -------------------------------------------------------------------------------- 1 | [{"Class":"1st","Sex":"Male","Age":"Child","Survived":"No","Freq":0},{"Class":"2nd","Sex":"Male","Age":"Child","Survived":"No","Freq":0},{"Class":"3rd","Sex":"Male","Age":"Child","Survived":"No","Freq":35},{"Class":"Crew","Sex":"Male","Age":"Child","Survived":"No","Freq":0},{"Class":"1st","Sex":"Female","Age":"Child","Survived":"No","Freq":0},{"Class":"2nd","Sex":"Female","Age":"Child","Survived":"No","Freq":0},{"Class":"3rd","Sex":"Female","Age":"Child","Survived":"No","Freq":17},{"Class":"Crew","Sex":"Female","Age":"Child","Survived":"No","Freq":0},{"Class":"1st","Sex":"Male","Age":"Adult","Survived":"No","Freq":118},{"Class":"2nd","Sex":"Male","Age":"Adult","Survived":"No","Freq":154},{"Class":"3rd","Sex":"Male","Age":"Adult","Survived":"No","Freq":387},{"Class":"Crew","Sex":"Male","Age":"Adult","Survived":"No","Freq":670},{"Class":"1st","Sex":"Female","Age":"Adult","Survived":"No","Freq":4},{"Class":"2nd","Sex":"Female","Age":"Adult","Survived":"No","Freq":13},{"Class":"3rd","Sex":"Female","Age":"Adult","Survived":"No","Freq":89},{"Class":"Crew","Sex":"Female","Age":"Adult","Survived":"No","Freq":3},{"Class":"1st","Sex":"Male","Age":"Child","Survived":"Yes","Freq":5},{"Class":"2nd","Sex":"Male","Age":"Child","Survived":"Yes","Freq":11},{"Class":"3rd","Sex":"Male","Age":"Child","Survived":"Yes","Freq":13},{"Class":"Crew","Sex":"Male","Age":"Child","Survived":"Yes","Freq":0},{"Class":"1st","Sex":"Female","Age":"Child","Survived":"Yes","Freq":1},{"Class":"2nd","Sex":"Female","Age":"Child","Survived":"Yes","Freq":13},{"Class":"3rd","Sex":"Female","Age":"Child","Survived":"Yes","Freq":14},{"Class":"Crew","Sex":"Female","Age":"Child","Survived":"Yes","Freq":0},{"Class":"1st","Sex":"Male","Age":"Adult","Survived":"Yes","Freq":57},{"Class":"2nd","Sex":"Male","Age":"Adult","Survived":"Yes","Freq":14},{"Class":"3rd","Sex":"Male","Age":"Adult","Survived":"Yes","Freq":75},{"Class":"Crew","Sex":"Male","Age":"Adult","Survived":"Yes","Freq":192},{"Class":"1st","Sex":"Female","Age":"Adult","Survived":"Yes","Freq":140},{"Class":"2nd","Sex":"Female","Age":"Adult","Survived":"Yes","Freq":80},{"Class":"3rd","Sex":"Female","Age":"Adult","Survived":"Yes","Freq":76},{"Class":"Crew","Sex":"Female","Age":"Adult","Survived":"Yes","Freq":20}] 2 | -------------------------------------------------------------------------------- /data/usarrests.json: -------------------------------------------------------------------------------- 1 | [{"Murder":13.2,"Assault":236,"UrbanPop":58,"Rape":21.2,"_row":"Alabama"},{"Murder":10,"Assault":263,"UrbanPop":48,"Rape":44.5,"_row":"Alaska"},{"Murder":8.1,"Assault":294,"UrbanPop":80,"Rape":31,"_row":"Arizona"},{"Murder":8.8,"Assault":190,"UrbanPop":50,"Rape":19.5,"_row":"Arkansas"},{"Murder":9,"Assault":276,"UrbanPop":91,"Rape":40.6,"_row":"California"},{"Murder":7.9,"Assault":204,"UrbanPop":78,"Rape":38.7,"_row":"Colorado"},{"Murder":3.3,"Assault":110,"UrbanPop":77,"Rape":11.1,"_row":"Connecticut"},{"Murder":5.9,"Assault":238,"UrbanPop":72,"Rape":15.8,"_row":"Delaware"},{"Murder":15.4,"Assault":335,"UrbanPop":80,"Rape":31.9,"_row":"Florida"},{"Murder":17.4,"Assault":211,"UrbanPop":60,"Rape":25.8,"_row":"Georgia"},{"Murder":5.3,"Assault":46,"UrbanPop":83,"Rape":20.2,"_row":"Hawaii"},{"Murder":2.6,"Assault":120,"UrbanPop":54,"Rape":14.2,"_row":"Idaho"},{"Murder":10.4,"Assault":249,"UrbanPop":83,"Rape":24,"_row":"Illinois"},{"Murder":7.2,"Assault":113,"UrbanPop":65,"Rape":21,"_row":"Indiana"},{"Murder":2.2,"Assault":56,"UrbanPop":57,"Rape":11.3,"_row":"Iowa"},{"Murder":6,"Assault":115,"UrbanPop":66,"Rape":18,"_row":"Kansas"},{"Murder":9.7,"Assault":109,"UrbanPop":52,"Rape":16.3,"_row":"Kentucky"},{"Murder":15.4,"Assault":249,"UrbanPop":66,"Rape":22.2,"_row":"Louisiana"},{"Murder":2.1,"Assault":83,"UrbanPop":51,"Rape":7.8,"_row":"Maine"},{"Murder":11.3,"Assault":300,"UrbanPop":67,"Rape":27.8,"_row":"Maryland"},{"Murder":4.4,"Assault":149,"UrbanPop":85,"Rape":16.3,"_row":"Massachusetts"},{"Murder":12.1,"Assault":255,"UrbanPop":74,"Rape":35.1,"_row":"Michigan"},{"Murder":2.7,"Assault":72,"UrbanPop":66,"Rape":14.9,"_row":"Minnesota"},{"Murder":16.1,"Assault":259,"UrbanPop":44,"Rape":17.1,"_row":"Mississippi"},{"Murder":9,"Assault":178,"UrbanPop":70,"Rape":28.2,"_row":"Missouri"},{"Murder":6,"Assault":109,"UrbanPop":53,"Rape":16.4,"_row":"Montana"},{"Murder":4.3,"Assault":102,"UrbanPop":62,"Rape":16.5,"_row":"Nebraska"},{"Murder":12.2,"Assault":252,"UrbanPop":81,"Rape":46,"_row":"Nevada"},{"Murder":2.1,"Assault":57,"UrbanPop":56,"Rape":9.5,"_row":"New Hampshire"},{"Murder":7.4,"Assault":159,"UrbanPop":89,"Rape":18.8,"_row":"New Jersey"},{"Murder":11.4,"Assault":285,"UrbanPop":70,"Rape":32.1,"_row":"New Mexico"},{"Murder":11.1,"Assault":254,"UrbanPop":86,"Rape":26.1,"_row":"New York"},{"Murder":13,"Assault":337,"UrbanPop":45,"Rape":16.1,"_row":"North Carolina"},{"Murder":0.8,"Assault":45,"UrbanPop":44,"Rape":7.3,"_row":"North Dakota"},{"Murder":7.3,"Assault":120,"UrbanPop":75,"Rape":21.4,"_row":"Ohio"},{"Murder":6.6,"Assault":151,"UrbanPop":68,"Rape":20,"_row":"Oklahoma"},{"Murder":4.9,"Assault":159,"UrbanPop":67,"Rape":29.3,"_row":"Oregon"},{"Murder":6.3,"Assault":106,"UrbanPop":72,"Rape":14.9,"_row":"Pennsylvania"},{"Murder":3.4,"Assault":174,"UrbanPop":87,"Rape":8.3,"_row":"Rhode Island"},{"Murder":14.4,"Assault":279,"UrbanPop":48,"Rape":22.5,"_row":"South Carolina"},{"Murder":3.8,"Assault":86,"UrbanPop":45,"Rape":12.8,"_row":"South Dakota"},{"Murder":13.2,"Assault":188,"UrbanPop":59,"Rape":26.9,"_row":"Tennessee"},{"Murder":12.7,"Assault":201,"UrbanPop":80,"Rape":25.5,"_row":"Texas"},{"Murder":3.2,"Assault":120,"UrbanPop":80,"Rape":22.9,"_row":"Utah"},{"Murder":2.2,"Assault":48,"UrbanPop":32,"Rape":11.2,"_row":"Vermont"},{"Murder":8.5,"Assault":156,"UrbanPop":63,"Rape":20.7,"_row":"Virginia"},{"Murder":4,"Assault":145,"UrbanPop":73,"Rape":26.2,"_row":"Washington"},{"Murder":5.7,"Assault":81,"UrbanPop":39,"Rape":9.3,"_row":"West Virginia"},{"Murder":2.6,"Assault":53,"UrbanPop":66,"Rape":10.8,"_row":"Wisconsin"},{"Murder":6.8,"Assault":161,"UrbanPop":60,"Rape":15.6,"_row":"Wyoming"}] 2 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject cljplot "0.0.4-SNAPSHOT" 2 | :description "JVM chart library" 3 | :url "https://github.com/generateme/cljplot" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.12.0"] 7 | [clojure2d "1.5.0-SNAPSHOT"] 8 | [clojure.java-time "1.4.2"] 9 | [org.clojure/data.csv "1.1.0"] 10 | [org.clojure/data.json "2.5.0"]] 11 | :repl-options {:timeout 120000} 12 | :java-source-paths ["src"] 13 | :resource-path "resources/" 14 | :javac-options ["--release" "8"] 15 | :target-path "target/%s") 16 | -------------------------------------------------------------------------------- /resources/clj-kondo.exports/cljplot/cljplot/config.edn: -------------------------------------------------------------------------------- 1 | {:hooks {:macroexpand {cljplot.common/do-graph hooks.common/do-graph 2 | cljplot.core/xy-chart hooks.common/xy-chart}}} 3 | -------------------------------------------------------------------------------- /resources/clj-kondo.exports/cljplot/cljplot/hooks/common.clj: -------------------------------------------------------------------------------- 1 | (ns hooks.common) 2 | 3 | (defmacro do-graph 4 | [graph-conf highest-render? & body] 5 | (let [c (symbol "c")] 6 | `(let [canv# (cljplot.common/graph-canvas ~graph-conf ~highest-render?) 7 | orient# (cljplot.common/canvas-orientation (:orientation ~graph-conf))] 8 | (cljplot.common/apply-body canv# orient# (fn [~c] ~@body)) 9 | canv#))) 10 | 11 | (defmacro xy-chart 12 | [conf series & mods] 13 | `(-> ~series 14 | ~@mods 15 | (cljplot.render/render-lattice ~conf))) 16 | -------------------------------------------------------------------------------- /results/anim/res.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/anim/res.gif -------------------------------------------------------------------------------- /results/bar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/bar.jpg -------------------------------------------------------------------------------- /results/bars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/bars.jpg -------------------------------------------------------------------------------- /results/box.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/box.jpg -------------------------------------------------------------------------------- /results/bubble.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/bubble.jpg -------------------------------------------------------------------------------- /results/connected.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/connected.jpg -------------------------------------------------------------------------------- /results/cont4_cont8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/cont4_cont8.jpg -------------------------------------------------------------------------------- /results/density-line.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/density-line.jpg -------------------------------------------------------------------------------- /results/density.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/density.jpg -------------------------------------------------------------------------------- /results/examples/acf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/acf.jpg -------------------------------------------------------------------------------- /results/examples/complex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/complex.jpg -------------------------------------------------------------------------------- /results/examples/contour.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/contour.jpg -------------------------------------------------------------------------------- /results/examples/contour2d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/contour2d.jpg -------------------------------------------------------------------------------- /results/examples/field-trace.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/field-trace.jpg -------------------------------------------------------------------------------- /results/examples/field.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/field.jpg -------------------------------------------------------------------------------- /results/examples/function2d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/function2d.jpg -------------------------------------------------------------------------------- /results/examples/gp-posterior.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/gp-posterior.jpg -------------------------------------------------------------------------------- /results/examples/gp-posteriors-20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/gp-posteriors-20.jpg -------------------------------------------------------------------------------- /results/examples/gp-predict.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/gp-predict.jpg -------------------------------------------------------------------------------- /results/examples/gp-priors-20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/gp-priors-20.jpg -------------------------------------------------------------------------------- /results/examples/heatmap-matrix-ann.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/heatmap-matrix-ann.jpg -------------------------------------------------------------------------------- /results/examples/heatmap-matrix.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/heatmap-matrix.jpg -------------------------------------------------------------------------------- /results/examples/heatmap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/heatmap.jpg -------------------------------------------------------------------------------- /results/examples/kernel-densities.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/kernel-densities.jpg -------------------------------------------------------------------------------- /results/examples/lag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/lag.jpg -------------------------------------------------------------------------------- /results/examples/lines.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/lines.jpg -------------------------------------------------------------------------------- /results/examples/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/logo.jpg -------------------------------------------------------------------------------- /results/examples/ma2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/ma2.jpg -------------------------------------------------------------------------------- /results/examples/point-cloud.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/point-cloud.jpg -------------------------------------------------------------------------------- /results/examples/ppplot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/ppplot.jpg -------------------------------------------------------------------------------- /results/examples/qqplot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/qqplot.jpg -------------------------------------------------------------------------------- /results/examples/random-walk-wrapped.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/random-walk-wrapped.jpg -------------------------------------------------------------------------------- /results/examples/strips.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/strips.jpg -------------------------------------------------------------------------------- /results/examples/vector-field.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/vector-field.jpg -------------------------------------------------------------------------------- /results/examples/vnoise.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/examples/vnoise.jpg -------------------------------------------------------------------------------- /results/functions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/functions.jpg -------------------------------------------------------------------------------- /results/histogram-percents.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/histogram-percents.jpg -------------------------------------------------------------------------------- /results/histogram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/histogram.jpg -------------------------------------------------------------------------------- /results/lattice/figure_1.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_1.1.jpg -------------------------------------------------------------------------------- /results/lattice/figure_1.2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_1.2.jpg -------------------------------------------------------------------------------- /results/lattice/figure_1.3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_1.3.jpg -------------------------------------------------------------------------------- /results/lattice/figure_13.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_13.1.jpg -------------------------------------------------------------------------------- /results/lattice/figure_13.2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_13.2.jpg -------------------------------------------------------------------------------- /results/lattice/figure_14.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_14.1.jpg -------------------------------------------------------------------------------- /results/lattice/figure_14.2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_14.2.jpg -------------------------------------------------------------------------------- /results/lattice/figure_14.3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_14.3.jpg -------------------------------------------------------------------------------- /results/lattice/figure_14.4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_14.4.jpg -------------------------------------------------------------------------------- /results/lattice/figure_2.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_2.1.jpg -------------------------------------------------------------------------------- /results/lattice/figure_2.10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_2.10.jpg -------------------------------------------------------------------------------- /results/lattice/figure_2.2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_2.2.jpg -------------------------------------------------------------------------------- /results/lattice/figure_2.3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_2.3.jpg -------------------------------------------------------------------------------- /results/lattice/figure_2.4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_2.4.jpg -------------------------------------------------------------------------------- /results/lattice/figure_2.6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_2.6.jpg -------------------------------------------------------------------------------- /results/lattice/figure_2.7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_2.7.jpg -------------------------------------------------------------------------------- /results/lattice/figure_2.8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_2.8.jpg -------------------------------------------------------------------------------- /results/lattice/figure_2.9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_2.9.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.1.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.10.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.11.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.12.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.13.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.14.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.15.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.16.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.2.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.2v2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.2v2.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.3.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.4.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.5.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.6.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.7.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.8.jpg -------------------------------------------------------------------------------- /results/lattice/figure_3.9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_3.9.jpg -------------------------------------------------------------------------------- /results/lattice/figure_4.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_4.1.jpg -------------------------------------------------------------------------------- /results/lattice/figure_4.2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_4.2.jpg -------------------------------------------------------------------------------- /results/lattice/figure_4.3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_4.3.jpg -------------------------------------------------------------------------------- /results/lattice/figure_4.4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_4.4.jpg -------------------------------------------------------------------------------- /results/lattice/figure_4.5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_4.5.jpg -------------------------------------------------------------------------------- /results/lattice/figure_4.6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_4.6.jpg -------------------------------------------------------------------------------- /results/lattice/figure_4.7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lattice/figure_4.7.jpg -------------------------------------------------------------------------------- /results/line.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/line.jpg -------------------------------------------------------------------------------- /results/lollipops.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lollipops.jpg -------------------------------------------------------------------------------- /results/lollipops2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/lollipops2.jpg -------------------------------------------------------------------------------- /results/min-max-mean.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/min-max-mean.jpg -------------------------------------------------------------------------------- /results/rug.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/rug.jpg -------------------------------------------------------------------------------- /results/rugs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/rugs.jpg -------------------------------------------------------------------------------- /results/scatter-sides.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/scatter-sides.jpg -------------------------------------------------------------------------------- /results/scatters2-rug.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/scatters2-rug.jpg -------------------------------------------------------------------------------- /results/strip-distorted.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/strip-distorted.jpg -------------------------------------------------------------------------------- /results/strip.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/strip.jpg -------------------------------------------------------------------------------- /results/vega/area-overlay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/area-overlay.jpg -------------------------------------------------------------------------------- /results/vega/area.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/area.jpg -------------------------------------------------------------------------------- /results/vega/bar-aggregate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/bar-aggregate.jpg -------------------------------------------------------------------------------- /results/vega/bar-color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/bar-color.jpg -------------------------------------------------------------------------------- /results/vega/bar-gantt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/bar-gantt.jpg -------------------------------------------------------------------------------- /results/vega/bar-grouped.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/bar-grouped.jpg -------------------------------------------------------------------------------- /results/vega/bar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/bar.jpg -------------------------------------------------------------------------------- /results/vega/box-plot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/box-plot.jpg -------------------------------------------------------------------------------- /results/vega/circle-binned.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/circle-binned.jpg -------------------------------------------------------------------------------- /results/vega/circle-bubble-hi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/circle-bubble-hi.jpg -------------------------------------------------------------------------------- /results/vega/circle-natural-disasters.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/circle-natural-disasters.jpg -------------------------------------------------------------------------------- /results/vega/circles.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/circles.jpg -------------------------------------------------------------------------------- /results/vega/color-with-shape.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/color-with-shape.jpg -------------------------------------------------------------------------------- /results/vega/connected-scatterplot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/connected-scatterplot.jpg -------------------------------------------------------------------------------- /results/vega/histogram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/histogram.jpg -------------------------------------------------------------------------------- /results/vega/layer-line-co2-concentration.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/layer-line-co2-concentration.jpg -------------------------------------------------------------------------------- /results/vega/line-color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/line-color.jpg -------------------------------------------------------------------------------- /results/vega/line-overlay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/line-overlay.jpg -------------------------------------------------------------------------------- /results/vega/line-spline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/line-spline.jpg -------------------------------------------------------------------------------- /results/vega/line-step.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/line-step.jpg -------------------------------------------------------------------------------- /results/vega/line.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/line.jpg -------------------------------------------------------------------------------- /results/vega/nulls.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/nulls.jpg -------------------------------------------------------------------------------- /results/vega/point-bubble.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/point-bubble.jpg -------------------------------------------------------------------------------- /results/vega/point-errorbar-ci.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/point-errorbar-ci.jpg -------------------------------------------------------------------------------- /results/vega/point-errorbar-stddev.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/point-errorbar-stddev.jpg -------------------------------------------------------------------------------- /results/vega/point2d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/point2d.jpg -------------------------------------------------------------------------------- /results/vega/stacked-area-normalize.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/stacked-area-normalize.jpg -------------------------------------------------------------------------------- /results/vega/stacked-area-stream.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/stacked-area-stream.jpg -------------------------------------------------------------------------------- /results/vega/stacked-area.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/stacked-area.jpg -------------------------------------------------------------------------------- /results/vega/stacked-bar-h.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/stacked-bar-h.jpg -------------------------------------------------------------------------------- /results/vega/stacked-bar-layer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/stacked-bar-layer.jpg -------------------------------------------------------------------------------- /results/vega/stacked-bar-normalize.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/stacked-bar-normalize.jpg -------------------------------------------------------------------------------- /results/vega/stacked-bar-weather.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/stacked-bar-weather.jpg -------------------------------------------------------------------------------- /results/vega/table-binned-heatmap-marginal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/table-binned-heatmap-marginal.jpg -------------------------------------------------------------------------------- /results/vega/table-binned-heatmap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/table-binned-heatmap.jpg -------------------------------------------------------------------------------- /results/vega/text-scatterplot-colored.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/text-scatterplot-colored.jpg -------------------------------------------------------------------------------- /results/vega/tick-dot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/tick-dot.jpg -------------------------------------------------------------------------------- /results/vega/tick-strip.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/tick-strip.jpg -------------------------------------------------------------------------------- /results/vega/trail-color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/vega/trail-color.jpg -------------------------------------------------------------------------------- /results/violin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/violin.jpg -------------------------------------------------------------------------------- /results/violins.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/generateme/cljplot/3004ae3a981f23c9d66d1caa8ab37cbf37996c0e/results/violins.jpg -------------------------------------------------------------------------------- /src/cljplot/axis.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.axis 2 | (:require [clojure2d.core :as c2d] 3 | [fastmath.core :as m] 4 | [cljplot.config :as cfg] 5 | [cljplot.common :as common] 6 | [clojure2d.color :as c] 7 | [fastmath.vector :as v])) 8 | 9 | (set! *warn-on-reflection* true) 10 | (set! *unchecked-math* :warn-on-boxed) 11 | (m/use-primitive-operators) 12 | 13 | (defn- axis-canvas 14 | "Return axis canvas 15 | 16 | Axis canvas is much bigger than axis itself." 17 | [^long axis-length] 18 | (let [size (+ axis-length 200)] 19 | (c2d/canvas size size :high))) 20 | 21 | (defn- axis-line 22 | "Draw line according to config. Canvas should be aligned to mid position." 23 | [canvas ^long length {:keys [color stroke ^double angle]}] 24 | (-> canvas 25 | (c2d/rotate (m/radians angle)) 26 | (c2d/translate (- (/ length 2)) 0) 27 | (c2d/set-color color) 28 | (c2d/set-stroke-custom stroke) 29 | (c2d/line 0 0 length 0))) 30 | 31 | ;; 32 | 33 | (defn- draw-tick 34 | "Just tick" 35 | [canvas type size] 36 | (case type 37 | :line (c2d/line canvas 0 0 0 size))) 38 | 39 | (defn- draw-text 40 | "Draw text on canvas for given parameters." 41 | [canvas txt shift-x shift-y-rel text-angle text-align angle] 42 | (-> canvas 43 | (c2d/push-matrix) 44 | (c2d/rotate (m/radians (- ^double text-angle ^double angle)))) 45 | (let [[_ ^double yoff _ ^double th] (c2d/text-bounding-box canvas txt)] 46 | (-> canvas 47 | (c2d/translate shift-x (int (+ (* th ^double shift-y-rel) yoff th))) 48 | (c2d/text txt 0 0 text-align) 49 | (c2d/pop-matrix)))) 50 | 51 | (defn- set-axis-font 52 | "Set font for ticks" 53 | ([canvas font font-size style] 54 | (when font (c2d/set-font canvas font)) 55 | (c2d/set-font-attributes canvas font-size style)) 56 | ([canvas font font-size] 57 | (when font (c2d/set-font canvas font)) 58 | (c2d/set-font-attributes canvas font-size))) 59 | 60 | (defn- draw-ticks 61 | "Draw ticks" 62 | [canvas length {:keys [scale ticks fmt]} angle {:keys [size type color stroke ^double anchor font-size font 63 | text-angle text-align shift-x shift-y-rel]}] 64 | (c2d/set-stroke-custom canvas stroke) ;; set ticks stroke 65 | (set-axis-font canvas font font-size) ;; set fonts 66 | (doseq [t ticks ;; for each tick 67 | :let [pos (m/floor (scale 0 length t)) ;; scale position 68 | sz (m/floor (size t)) ;; calc size 69 | ty (* -1.0 anchor sz)]] 70 | (-> canvas 71 | (c2d/set-color color) 72 | (c2d/push-matrix) 73 | (c2d/translate pos 0) 74 | (c2d/translate 0 ty) 75 | (draw-tick type (* anchor sz)) ;; draw tick 76 | (draw-text (fmt t) shift-x shift-y-rel text-angle text-align angle) 77 | (c2d/pop-matrix))) 78 | canvas) 79 | 80 | (defn- draw-axis 81 | "Draw axis and ticks" 82 | [length scale-info config] 83 | (let [canvas (axis-canvas length) ;; create canvas 84 | mid (/ (c2d/width canvas) 2)] ;; calc mid point 85 | (c2d/with-canvas [c canvas] 86 | (-> c 87 | (c2d/translate mid mid) ;; go to mid 88 | (axis-line length (:line config)) 89 | (draw-ticks length scale-info 90 | (:angle (:line config)) 91 | (:ticks config))) ;; draw ticks and labels 92 | {:canvas canvas 93 | :fixed? true 94 | :anchor (-> (c2d/transform c 0 0) 95 | (v/fmap m/floor) 96 | (v/sub) 97 | (v/sub [0 1]))}))) 98 | 99 | (defn- find-max-tick-size 100 | "Find maximum tick size." 101 | [{:keys [ticks]} config] 102 | (let [size-fn (-> config :ticks :size)] 103 | (max 0.0 (inc (double (-> config :line :stroke :size))) 104 | ^double (reduce m/fast-max (map #(size-fn % config) ticks))))) 105 | 106 | (defn- find-text-bounding-box 107 | "Find biggest bounding box from ticks" 108 | [{:keys [ticks fmt]} config] 109 | (c2d/with-canvas [c (c2d/canvas 1 1)] 110 | (set-axis-font c (get-in config [:ticks :font]) (-> config :ticks :font-size)) 111 | (reduce (fn [[^double w ^double h] t] 112 | (let [s (fmt t) 113 | [_ _ ^double cw ^double ch] (c2d/text-bounding-box c s)] 114 | [(max w cw) (max h ch)])) [0 0] ticks))) 115 | 116 | (defn- xy-axes 117 | [position scale-info config {:keys [w]}] 118 | (let [a (draw-axis w scale-info config)] 119 | (if (= :x position) 120 | (update a :anchor v/sub (v/vec2 0.0 0.0)) 121 | (update-in a [:anchor 1] clojure.core/+ w)))) 122 | 123 | (defn axis-size 124 | [scale position config] 125 | (let [[^double bw ^double bh] (find-text-bounding-box scale config) 126 | ^double l (find-max-tick-size scale config)] 127 | (m/ceil (if (= :x position) 128 | (+ bh 5 l) 129 | (+ bw 10 l))))) 130 | 131 | (defmethod common/data-extent :axis [_ _ _] nil) 132 | (defmethod common/prepare-data :axis [_ d _] d) 133 | 134 | (defmethod common/render-graph :axis [_ position config chart-data] 135 | (xy-axes position (:x chart-data) config chart-data)) 136 | 137 | ;;;;;;;;;;;;;;;;;;;; 138 | 139 | (defmethod common/data-extent :grid [_ _ _] nil) 140 | (defmethod common/prepare-data :grid [_ _ _] nil) 141 | 142 | (defmethod common/render-graph :grid [_ _ config {:keys [w h x y] :as chart-data}] 143 | (let [scale-x (:scale x) 144 | ticks-x (:ticks x) 145 | scale-y (:scale y) 146 | ticks-y (:ticks y)] 147 | (common/do-graph chart-data false 148 | (when-let [x (:x config)] 149 | (let [{:keys [color stroke]} x] 150 | (c2d/set-color c color) 151 | (c2d/set-stroke-custom c stroke) 152 | (doseq [t ticks-x 153 | :let [xpos (m/floor (scale-x 0 w t))]] 154 | (c2d/line c xpos 0 xpos h)))) 155 | 156 | (when-let [y (:y config)] 157 | (let [{:keys [color stroke]} y] 158 | (c2d/set-color c color) 159 | (c2d/set-stroke-custom c stroke) 160 | (doseq [t ticks-y 161 | :let [ypos (inc (m/floor (scale-y 0 h t)))]] 162 | (c2d/line c 0 ypos w ypos))))))) 163 | 164 | 165 | ;; legends 166 | 167 | (defn- legend-shape-mark 168 | [canvas ^long marker-size ^long h {:keys [shape color size stroke] 169 | :or {size 6}}] 170 | (let [h2 (/ h 2)] 171 | (common/draw-shape canvas (/ marker-size 2) h2 shape color stroke size))) 172 | 173 | (defn- legend-line-mark 174 | [canvas ^long marker-size ^long h {:keys [stroke color shape] :as conf}] 175 | (let [h2 (/ h 2)] 176 | (when stroke (c2d/set-stroke-custom canvas stroke)) 177 | (c2d/set-color canvas color) 178 | (c2d/line canvas 0 h2 marker-size h2) 179 | (when shape (legend-shape-mark canvas marker-size h conf)))) 180 | 181 | (defn- legend-rect-mark 182 | [canvas ^long marker-size ^long h {:keys [color]}] 183 | (c2d/filled-with-stroke canvas color (c/darken color) c2d/rect 0 1 marker-size (dec h))) 184 | 185 | (defn- legend-circle-mark 186 | [canvas ^long marker-size ^long h {:keys [color size] :or {size 10}}] 187 | (c2d/set-color canvas color) 188 | (c2d/ellipse canvas (/ marker-size 2) (/ h 2) size size)) 189 | 190 | (defn legends-sizes 191 | ([name ls gap] (legends-sizes name ls gap nil 12)) 192 | ([name ls gap font-size] (legends-sizes name ls gap nil font-size)) 193 | ([name ls gap font font-size] 194 | (c2d/with-canvas [c (c2d/canvas 1 1)] 195 | (set-axis-font c font font-size :normal) 196 | (let [[^double mw ^double mh] (map #(m/ceil %) 197 | (reduce (fn [[^double w ^double h] t] 198 | (let [[_ _ ^double cw ^double ch] (c2d/text-bounding-box c t)] 199 | [(max w cw) (max h ch)])) [0 0] (map second ls)))] 200 | (c2d/set-font-attributes c font-size :bold) 201 | (let [[^double lw ^double lh] (map #(m/ceil %) (drop 2 (c2d/text-bounding-box c name)))] 202 | [(inc lh) (max mw lw) (m/ceil (+ (inc lh) ^int gap mh (* (count ls) (+ ^int gap (inc mh)))))]))))) 203 | 204 | (defn legends 205 | ([data] (legends data {})) 206 | ([data conf] 207 | (let [{:keys [^int gap ^int marker-size font font-size color]} (cfg/merge-configuration :legend conf) 208 | sizes (map (fn [[k ls]] (legends-sizes k ls gap font font-size)) data) 209 | 210 | ^int h (reduce m/+ (map last sizes)) 211 | w (+ marker-size (* 3 gap) ^int (reduce m/max (map second sizes))) 212 | ^int grouph (reduce m/max (map first sizes)) 213 | c (c2d/canvas (+ 50 w) (+ 50 h))] 214 | 215 | (c2d/with-canvas [c c] 216 | (c2d/translate c (+ gap 25) 25) 217 | 218 | (doseq [[k ls] data] 219 | 220 | (let [[^double sx ^double sy] (map #(m/ceil %) (c2d/text-bounding-box c k))] 221 | (-> (set-axis-font c font font-size :bold) 222 | (c2d/set-color color) 223 | (c2d/push-matrix) 224 | (c2d/translate sx (- sy)) 225 | (c2d/text k 0 0) 226 | (c2d/pop-matrix) 227 | (c2d/translate 0 (+ gap grouph)))) 228 | 229 | (doseq [[type title conf] ls 230 | :let [[^double sx ^double sy ^double _bw ^double bh] (map #(m/ceil %) (c2d/text-bounding-box c title))]] 231 | 232 | (case type 233 | :line (legend-line-mark c marker-size bh conf) 234 | :rect (legend-rect-mark c marker-size bh conf) 235 | :shape (legend-shape-mark c marker-size bh conf) 236 | :circle (legend-circle-mark c marker-size bh conf)) 237 | 238 | (-> c 239 | (set-axis-font font font-size :normal) 240 | (c2d/push-matrix) 241 | (c2d/translate (+ gap marker-size sx) (inc (- sy))) 242 | (c2d/set-color :black) 243 | (c2d/text title 0 0) 244 | (c2d/pop-matrix) 245 | (c2d/translate 0 (+ bh gap)))) 246 | (c2d/translate c 0 grouph)) 247 | {:canvas c 248 | :anchor [-25 -25] 249 | :block-size w})))) 250 | 251 | ;; 252 | 253 | (defn gradient-width 254 | ^long [{:keys [^int gap ^int marker-size font font-size]} title mn mx] 255 | (c2d/with-canvas [c (c2d/canvas 1 1)] 256 | (set-axis-font c font font-size :bold) 257 | (max (c2d/text-width c title) 258 | (+ marker-size gap gap (max (c2d/text-width c mn) 259 | (c2d/text-width c mx)))))) 260 | 261 | (defn gradient 262 | [gradient w h title mn mx conf] 263 | (let [{:keys [^int gap ^int marker-size font font-size color]} (cfg/merge-configuration :gradient conf) 264 | c (c2d/canvas (+ ^long w 50) (+ ^long h 50))] 265 | (c2d/with-canvas [c c] 266 | (c2d/translate c (+ gap 25) 25) 267 | 268 | (let [[^double sx ^double sy ^double _bw ^double bh] (map #(m/ceil %) (c2d/text-bounding-box c title)) 269 | gh (- ^int h bh gap)] 270 | (-> (c2d/set-color c color) 271 | (set-axis-font font font-size :bold) 272 | (c2d/push-matrix) 273 | (c2d/translate sx (- sy)) 274 | (c2d/text title 0 0) 275 | (c2d/pop-matrix) 276 | (c2d/translate 0 (+ bh gap)) 277 | (set-axis-font font font-size :normal) 278 | (c2d/push-matrix) 279 | (c2d/translate sx (- sy)) 280 | (c2d/text mx (+ marker-size gap) 0) 281 | (c2d/translate 0 (- gh bh)) 282 | (c2d/text mn (+ marker-size gap) 0) 283 | (c2d/pop-matrix)) 284 | 285 | (dotimes [id gh] 286 | (let [gid (m/norm id 0 h 1.0 0.0)] 287 | (c2d/set-color c (gradient gid)) 288 | (c2d/line c 0 id marker-size id))))) 289 | 290 | {:canvas c 291 | :anchor [-25 -25]})) 292 | 293 | (m/unuse-primitive-operators) 294 | 295 | 296 | #_(cc/show-image (:canvas (gradient (c/gradient :red-blue) 130 200 "ABBA babba" -10 20 (cfg/get-configuration :gradient)))) 297 | 298 | #_(cc/show-image (:canvas (legends {"First" [[:line "ABC" {:shape \A :color :blue}] 299 | [:line "ABCDDD" {:shape \A :color :blue}] 300 | [:line "ABCFFFFFfff" {:shape \A :color :blue}]] 301 | "Second" [[:rect "ABC" {:shape \A :color :blue}] 302 | [:rect "ABCDDD" {:shape \A :color :blue}] 303 | [:rect "ABCFFFFFfff" {:shape \A :color :blue}]]}))) 304 | 305 | #_(require '[clojure2d.extra.utils :as cc]) 306 | 307 | #_(cc/show-image (:canvas (common/legend "This is a title" [[:line "asdf" {:shape \A :color :blue}] [:line "This is longer line" {:color :maroon}] [:line 333 {:color :gray}] [:shape "Shape only" {:shape \s :color :blue}] [:rect "Rectangle" {:color :dark-olivegreen}]])) "legend1.jpg") 308 | 309 | #_(cc/show-image (save (:canvas (legend "This is a title" [[:circle "asdf" {:size 20 :color :blue}] [:circle "Middle circle" {:color :maroon :size 25}] [:circle 333 {:color :blue :size 30}]])) "legend2.jpg")) 310 | -------------------------------------------------------------------------------- /src/cljplot/build.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.build 2 | (:require [cljplot.common :as common] 3 | [cljplot.config :as cfg] 4 | [cljplot.axis :as axis] 5 | [cljplot.scale :as s] 6 | [fastmath.core :as m])) 7 | 8 | (set! *warn-on-reflection* true) 9 | (set! *unchecked-math* :warn-on-boxed) 10 | (m/use-primitive-operators) 11 | 12 | ;; 13 | 14 | (defn series 15 | "Pack series into list" 16 | [& series] (vec series)) 17 | 18 | (defn add-serie 19 | "Append series" 20 | ([series [t d c] x y] 21 | (conj series [t d (assoc c :position [x y])])) 22 | ([series serie] 23 | (add-serie series serie 0 0))) 24 | 25 | (def add-series (comp vec concat)) 26 | 27 | (defn add-multi 28 | "Create definition for multi datasets from a map for overlays and append" 29 | ([series serie-name map-of-data] (add-multi series serie-name map-of-data {})) 30 | ([series serie-name map-of-data serie-config] (add-multi series serie-name map-of-data serie-config {})) 31 | ([series serie-name map-of-data serie-config multi-config] 32 | (let [mconfig (common/map-kv cycle multi-config)] 33 | (reduce conj series 34 | (for [[idx [k d]] (map-indexed vector map-of-data) 35 | :let [nconfig (reduce-kv (fn [m ky v] 36 | ((if (sequential? ky) assoc-in assoc) m ky (nth v idx))) serie-config mconfig)]] 37 | [serie-name d (assoc nconfig :serie-name k)]))))) 38 | 39 | (defn- find-most-squared-shape 40 | "Let's find best squared shape for given number of data" 41 | [^long v] 42 | (let [s (m/sqrt v) 43 | r (range 1 (inc v)) 44 | [_ ^long x ^long y] (first (sort-by first clojure.core/< (for [^long x r ^long y r 45 | :let [d1 (- (* x y) v) 46 | d (+ d1 d1 (+ (m/sq (- s x)) 47 | (m/sq (- s y))))] 48 | :when (>= d1 0.0)] 49 | [d x y])))] 50 | (if (< x y) [x y] [y x]))) 51 | 52 | (def ^:private find-most-squared-shape+ (memoize find-most-squared-shape)) 53 | 54 | (defn- ensure-rows-cols 55 | [shape ^long total] 56 | (let [total (double total) 57 | [^long rows ^long cols] (map #(when (and % (pos? ^long %)) %) shape)] 58 | (cond 59 | (and rows cols) [rows cols] 60 | rows [rows (int (m/ceil (/ total rows)))] 61 | cols [(int (m/ceil (/ total cols))) cols] 62 | :else (find-most-squared-shape+ total)))) 63 | 64 | (defn lattice 65 | "Pack series into lattice" 66 | ([serie-type data] (lattice serie-type data nil)) 67 | ([serie-type data serie-config] (lattice serie-type data serie-config nil)) 68 | ([serie-type data serie-config conf] 69 | (let [[rows cols] (ensure-rows-cols (:shape conf) (count data)) 70 | positions (for [y (range rows) x (range cols)] [x y]) 71 | grid-conf (when-let [gc (:grid conf)] 72 | (if (map? gc) gc {})) 73 | label (when-let [lc (:label conf)] 74 | (if (string? lc) (partial format lc) lc))] 75 | (mapcat (fn [[k v] p] 76 | (let [with-label (if label (assoc serie-config :label (label k)) serie-config) 77 | s [serie-type v (assoc with-label :position p)]] 78 | (if-not grid-conf [s] 79 | [[:grid nil (assoc grid-conf :position p)] s]))) data positions)))) 80 | 81 | ;; 82 | 83 | (defn- add-default-position 84 | "Add default position to config" 85 | [[t d c]] [t d (if (contains? c :position) c (assoc c :position [0 0]))]) 86 | 87 | (defn- group-by-position 88 | "Create a map of series grouped by chart positions. 89 | Additionally find number of rows and cols. Default position is [0,0]." 90 | [srs] 91 | (let [gsrs (group-by (comp :position last) (map add-default-position srs)) 92 | [cols rows] (map #(inc ^long (apply clojure.core/max (mapv % (keys gsrs)))) [first second])] 93 | {:series gsrs 94 | :cols cols 95 | :rows rows})) 96 | 97 | (defn- add-series-info 98 | "Add series id and chart type to configuration" 99 | [id [t d c]] [t d (-> (cfg/merge-configuration t (or c {})) 100 | (assoc :series-id id :chart-type t))]) 101 | 102 | (defn- chart-process-data 103 | "Prepare data for given chart type" 104 | [f [t d c]] [t (f t d c) c]) 105 | 106 | (defn- calculate-extent 107 | [[t d c]] 108 | [t d (assoc c :extent (common/extend-domains (common/data-extent t d c) (:margins c)))]) 109 | 110 | (defn- preprocess-steps 111 | [s] 112 | (into [] (comp 113 | (map-indexed add-series-info) ;; add series-id 114 | (map (partial chart-process-data common/prepare-data)) ;; precalculate data 115 | (map calculate-extent)) ;; calculate extents 116 | s)) 117 | 118 | (defn- adjust-configs-and-preprocess 119 | "Insert additional information to config and merge with defaults. 120 | Calculate extents and preprocess data in one step." 121 | [srs] 122 | (update srs :series #(common/map-kv preprocess-steps %))) 123 | 124 | ;; awful part... 125 | 126 | (defn- select-row-col-ids 127 | "Select keys for given row (1) or column (0)." 128 | [k ^long id m] 129 | (filter #(== id ^long (% k)) (keys m))) 130 | 131 | (defn- merge-extents-by-ids 132 | "Merge extents by column/row" 133 | [exts cnt pos k] 134 | (into {} (->> (range cnt) 135 | (map (fn [id] 136 | [id (->> exts 137 | (select-row-col-ids pos id) 138 | (mapcat exts) 139 | (map k) 140 | (common/find-min-max))])) 141 | (remove (comp nil? second))))) 142 | 143 | ;; TODO: merge all other extents globally (like :inner) 144 | 145 | (defn- merge-extents 146 | "Find biggest extent for each grid position." 147 | [{:keys [rows cols] :as srs}] 148 | (let [exts (common/map-kv (partial map (comp :extent last)) (:series srs))] 149 | (assoc srs :extents {:x (merge-extents-by-ids exts cols 0 :x) 150 | :y (merge-extents-by-ids exts rows 1 :y)}))) 151 | 152 | ;; 153 | 154 | (def ^:private default-scale-defs 155 | {:numerical [:linear] 156 | :temporal [:time] 157 | :categorical [:bands]}) 158 | 159 | (defn- auto-scale 160 | ([series x-or-y] 161 | (assoc-in series [:scales x-or-y] (->> (get-in series [:extents x-or-y]) 162 | (common/map-kv (fn [[t domain conf]] 163 | (let [t (get default-scale-defs t [:linear])] 164 | (s/scale-map (if conf (conj t conf) t) 165 | {:domain domain})))))))) 166 | 167 | (defn- auto-scales 168 | [series] 169 | (-> series 170 | (auto-scale :x) 171 | (auto-scale :y))) 172 | 173 | (defn preprocess-series 174 | [series] 175 | (-> series 176 | (group-by-position) 177 | (adjust-configs-and-preprocess) 178 | (merge-extents) 179 | (auto-scales))) 180 | 181 | (defn update-scale 182 | ([series axis k v] (update-scale series axis 0 k v)) 183 | ([series axis pos k v] 184 | (update-in series [:scales axis pos] s/update-scale k v))) 185 | 186 | (defn update-scales 187 | [series axis k v] 188 | (reduce #(update-scale %1 axis %2 k v) series (-> series :scales axis keys))) 189 | 190 | (defn tie-domains 191 | [series & axes] 192 | (reduce #(update-scales %1 %2 :domain (second (common/find-min-max (-> %1 :extents %2 vals)))) series axes)) 193 | 194 | (defn- find-size 195 | [side-nseries] 196 | (let [s (remove nil? (map (comp :block-size second) side-nseries))] 197 | (when (seq s) (reduce m/max s)))) 198 | 199 | (defn- append-side 200 | [series side pos size side-nseries] 201 | (let [s (update (get series side {pos []}) pos conj {:size (or (find-size side-nseries) size) :series side-nseries})] 202 | (assoc series side s))) 203 | 204 | (def ^:private position->scale-id {:bottom :x :top :x :left :y :right :y}) 205 | 206 | (defn add-axes 207 | ([series side] (add-axes series side {})) 208 | ([series side config] 209 | (let [conf-name (keyword (str "axis-" (name side))) 210 | config (cfg/merge-configuration conf-name config) 211 | scale-id (position->scale-id side)] 212 | (reduce (fn [s [pos scale]] 213 | (let [size (axis/axis-size scale scale-id config)] 214 | (append-side s side pos size [[:axis scale-id config]]))) series (get (:scales series) scale-id))))) 215 | 216 | (defn add-side 217 | ([series side side-series] (add-side series side 50 side-series)) 218 | ([series side size side-series] (add-side series side 0 size side-series)) 219 | ([series side pos size side-series] 220 | (append-side series side pos size (preprocess-steps side-series)))) 221 | 222 | (defn add-label 223 | ([series side label] (add-label series side label {})) 224 | ([series side label conf] 225 | (let [conf (cfg/merge-configuration :label conf) 226 | data (common/prepare-data :label label conf)] 227 | (assoc-in series [:labels side] data)))) 228 | 229 | (defn add-legend 230 | [series name defs] 231 | (if (seq defs) 232 | (update series :legend update name (fn [v] (vec (if (seq v) (concat v defs) defs)))) 233 | series)) 234 | 235 | (m/unuse-primitive-operators) 236 | -------------------------------------------------------------------------------- /src/cljplot/common.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.common 2 | (:require [clojure2d.core :as c2d] 3 | [clojure2d.color :as c] 4 | [fastmath.stats :as stats] 5 | [fastmath.grid :as grid] 6 | [fastmath.vector :as v] 7 | [fastmath.core :as m] 8 | [clojure.data.csv :as csv] 9 | [clojure.data.json :as json] 10 | [clojure.java.io :as io] 11 | [java-time :as dt] 12 | [cljplot.scale :as s])) 13 | 14 | (set! *unchecked-math* :warn-on-boxed) 15 | (m/use-primitive-operators) 16 | 17 | (defn graph-canvas 18 | "Create canvas to draw a chart on" 19 | ([graph-conf] (graph-canvas graph-conf false)) 20 | ([{:keys [w h orientation rendering-hint ^double oversize] :or {orientation :top oversize 100}} highest?] 21 | (let [[^int cw ^int ch] (if (#{:left :right} orientation) [h w] [w h]) 22 | canvas-shift (/ oversize 2) 23 | canvas-shift- (- canvas-shift) 24 | c (c2d/canvas (+ oversize cw) (+ oversize ch) (if rendering-hint 25 | rendering-hint 26 | (if highest? :highest :high)))] 27 | {:canvas c 28 | :anchor [canvas-shift- canvas-shift-] 29 | :shift [canvas-shift canvas-shift] 30 | :w w 31 | :h h}))) 32 | 33 | (defn canvas-orientation 34 | "Convert layout orientation to canvas orientations" 35 | [orient] 36 | (get {:bottom :top-left- :top :bottom-left+ :left :bottom-right+ :right :bottom-left-} orient :bottom-left+)) 37 | 38 | (defn apply-body 39 | [canv orient f] 40 | (c2d/with-oriented-canvas orient [c (:canvas canv)] 41 | (c2d/translate c (:shift canv)) 42 | (f c))) 43 | 44 | (defmacro do-graph 45 | "Wrap canvas creation and orientation." 46 | {:style/indent 2} 47 | ([graph-conf highest-render? & body] 48 | (let [c (symbol "c")] 49 | `(let [canv# (graph-canvas ~graph-conf ~highest-render?) 50 | orient# (canvas-orientation (:orientation ~graph-conf))] 51 | (apply-body canv# orient# (fn [~c] ~@body)) 52 | canv#)))) 53 | 54 | ;; 55 | 56 | (defn date-time? 57 | [t] 58 | (instance? java.time.temporal.Temporal t)) 59 | 60 | (defn wrap-interpolator-for-dt 61 | "Wrap interpolator to work with date/time values." 62 | [interpolator domain x y] 63 | (if (date-time? (first x)) 64 | (let [scale (s/time-interval domain) 65 | interp (interpolator (mapv scale x) y)] 66 | (fn [v] 67 | (interp (scale v)))) 68 | (interpolator x y))) 69 | 70 | ;; 71 | 72 | (defn deep-merge 73 | "Merge maps on every level." 74 | [a b] (if (and (map? a) (map? b)) (merge-with deep-merge a b) b)) 75 | 76 | (defn map-kv [f coll] 77 | (reduce-kv (fn [m k v] (assoc m k (f v))) (empty coll) coll)) 78 | 79 | (defn find-min-max 80 | "For given list of vectors find maximum extent." 81 | [s] 82 | (let [s (filter seq s)] 83 | (when (seq s) 84 | (assert (-> (map first s) 85 | (set) 86 | (count) 87 | (dec) 88 | (zero?)) "Types of series should have the same type: continuous or categorical") 89 | (let [[t _ sconf] (first s) 90 | res [t (if (#{:numerical :temporal} t) 91 | (let [[fmin fmax] (if (= t :temporal) [dt/min dt/max] [m/fast-min m/fast-max])] 92 | (reduce (fn [[ca cb] [a b]] [(fmin ca a) (fmax cb b)]) (map second s))) 93 | (distinct (mapcat identity (map second s))))]] 94 | (if sconf (conj res sconf) res))))) 95 | 96 | (defn extent 97 | [data] 98 | (let [data (remove #(or (nil? %) 99 | (and (number? %) 100 | (m/invalid-double? %))) data) 101 | v (first data)] 102 | (cond 103 | (date-time? v) [:temporal [(reduce dt/min data) (reduce dt/max data)]] 104 | (number? v) [:numerical (take 2 (stats/extent data))]))) 105 | 106 | ;; 107 | 108 | (defn bands->positions-size 109 | [bands ^double size] 110 | (into {} (mapv (fn [id] 111 | (let [{:keys [^double start ^double end]} (bands id) 112 | ss (m/round (- (* size end) (* size start))) 113 | st (m/round (* size start))] 114 | [id [st ss]])) (:domain bands)))) 115 | 116 | (defn common-extent 117 | "Calculate extent for axes" 118 | ([data] (common-extent data first second #(nth % 2))) 119 | ([data selector-x selector-y selector-z] 120 | (if-not (sequential? (first data)) 121 | {:x (extent data) 122 | :y [:numerical [0.0 1.0]]} 123 | (let [cnt (count (first data))] 124 | (cond-> {} 125 | (pos? cnt) (assoc :x (extent (map selector-x data))) 126 | (> cnt 1) (assoc :y (extent (map selector-y data))) 127 | (> cnt 2) (assoc :z (extent (map selector-z data)))))))) 128 | 129 | 130 | (defn extend-domain-numerical 131 | [[^double start ^double end] [^double l ^double r]] 132 | (let [diff (- end start)] 133 | [(- start (* diff l)) 134 | (+ end (* diff r))])) 135 | 136 | (defn- extend-domain 137 | [[t domain :as all] margin] 138 | (case t 139 | :numerical [t (extend-domain-numerical domain margin)] 140 | all)) 141 | 142 | (defn- check-and-extend 143 | [extent margin] 144 | (if (and extent margin) 145 | (extend-domain extent margin) 146 | extent)) 147 | 148 | (defn extend-domains 149 | [extents margins] 150 | (-> extents 151 | (update :x check-and-extend (:x margins)) 152 | (update :y check-and-extend (:y margins)))) 153 | 154 | (defn extract-first [data] 155 | (if (sequential? (first data)) 156 | (map first data) 157 | data)) 158 | 159 | (defn coerce-format-fn 160 | "Find formating funciton." 161 | [fmt] 162 | (cond 163 | (string? fmt) (partial format fmt) 164 | (fn? fmt) fmt 165 | :else str)) 166 | 167 | 168 | ;; 169 | 170 | (defmulti data-extent (fn [t _data _config] t)) 171 | (defmulti render-graph (fn [t _data _config _chart-data] t)) 172 | (defmulti prepare-data (fn [t _data _config] t)) 173 | (defmulti postprocess-data (fn [t _data _config] t)) 174 | 175 | (defmethod data-extent :default [_ data _] (common-extent data)) 176 | (defmethod prepare-data :default [_ data _] data) 177 | (defmethod postprocess-data :default [_ data _] data) 178 | (defmethod render-graph :default [_ _ _ _chart-data] (do-graph _chart-data false)) 179 | 180 | (defmethod data-extent :empty [_ _ _] {}) 181 | 182 | ;; 183 | 184 | (defn get-scale 185 | "Return scale from series" 186 | [series key] 187 | (:scale (series key))) 188 | 189 | (defn get-width 190 | [series] 191 | (:size (:x series))) 192 | 193 | (defn get-height 194 | [series] 195 | (:size (:x series))) 196 | 197 | ;; 198 | 199 | (defn heatmap-grid 200 | "Snap normalized coords from vx to grid cell midpoints." 201 | [vx scale-x scale-y gtype cells] 202 | (let [iscale-x (:inverse scale-x) 203 | iscale-y (:inverse scale-y) 204 | g (grid/grid gtype (/ (double cells))) 205 | cnts (reduce (fn [m [x y cnt]] 206 | (let [cnt (or cnt 1) 207 | cell (grid/coords->mid g (v/vec2 (scale-x x) (scale-y y)))] 208 | (if (contains? m cell) 209 | (update m cell m/+ cnt) 210 | (assoc m cell cnt)))) {} vx)] 211 | (map (fn [[[x y] cnt]] 212 | (v/vec3 (iscale-x x) (iscale-y y) cnt)) cnts))) 213 | 214 | ;; 215 | 216 | (defn- triangle-shape 217 | [canv x y hsize size angle stroke?] 218 | (let [size (double size) 219 | hsize (double hsize) 220 | size3 (/ size 3.0) 221 | size6 (+ size3 size3)] 222 | (-> canv 223 | (c2d/push-matrix) 224 | (c2d/translate x y) 225 | (c2d/rotate (m/radians (double angle))) 226 | (c2d/triangle (- hsize) (- size3) 227 | (+ hsize) (- size3) 228 | 0 (+ size6) stroke?) 229 | (c2d/pop-matrix)))) 230 | 231 | (defn draw-shape 232 | [canv x y type color stroke size] 233 | (-> canv 234 | (c2d/set-stroke-custom stroke) 235 | (c2d/set-color color)) 236 | (let [size (double size) 237 | x (double x) 238 | y (double y) 239 | hsize (/ size 2.0)] 240 | (case type 241 | \* (-> canv 242 | (c2d/set-font-attributes (* 2 size)) 243 | (c2d/text (str type) x (+ (- (c2d/font-height canv) (* 0.6666 (c2d/font-ascent canv))) y) :center)) 244 | \} (c2d/filled-with-stroke canv color (c/darken color) triangle-shape x y hsize size -90) 245 | \{ (c2d/filled-with-stroke canv color (c/darken color) triangle-shape x y hsize size 90) 246 | \A (c2d/filled-with-stroke canv color (c/darken color) triangle-shape x y hsize size 180) 247 | \V (c2d/filled-with-stroke canv color (c/darken color) triangle-shape x y hsize size 0) 248 | \v (triangle-shape canv x y hsize size 0 true) 249 | \> (triangle-shape canv x y hsize size -90 true) 250 | \< (triangle-shape canv x y hsize size 90 true) 251 | \^ (triangle-shape canv x y hsize size 180 true) 252 | \x (-> canv 253 | (c2d/line (- x hsize) (+ y hsize) (+ x hsize) (- y hsize)) 254 | (c2d/line (- x hsize) (- y hsize) (+ x hsize) (+ y hsize))) 255 | \/ (c2d/line canv (- x hsize) (+ y hsize) (+ x hsize) (- y hsize)) 256 | \\ (c2d/line canv (- x hsize) (- y hsize) (+ x hsize) (+ y hsize)) 257 | \+ (-> canv 258 | (c2d/line (- x hsize) y (+ x hsize) y) 259 | (c2d/line x (- y hsize) x (+ y hsize))) 260 | \- (c2d/line canv (- x hsize) y (+ x hsize) y) 261 | \| (c2d/line canv x (- y hsize) x (+ y hsize)) 262 | \s (c2d/crect canv x y size size true) 263 | \S (c2d/filled-with-stroke canv color (c/darken color) c2d/crect x y size size) 264 | \o (c2d/ellipse canv x y size size true) 265 | \O (c2d/filled-with-stroke canv color (c/darken color) c2d/ellipse x y size size) 266 | \. (c2d/point canv x y) 267 | (let [[^double sx ^double sy] (map #(m/ceil %) (c2d/text-bounding-box canv (str type)))] 268 | (-> canv 269 | (c2d/push-matrix) 270 | (c2d/translate (+ x sx) (- y (/ sy 2))) 271 | (c2d/set-font-attributes size) 272 | (c2d/text (str type) 0 0 :center) 273 | (c2d/pop-matrix)))))) 274 | 275 | ;; 276 | 277 | (defn transformed-text 278 | [c s x y & r] 279 | (c2d/push-matrix c) 280 | (let [[nx ny] (c2d/transform c x y)] 281 | (c2d/reset-matrix c) 282 | (apply c2d/text c s nx ny r) 283 | (c2d/pop-matrix c))) 284 | 285 | (def line-dash-styles 286 | (cycle [[1 1] [2 2] [4 4] [5 1 3] [4 1] [10 2] [14 2 7 2] [14 2 2 7] [2 2 20 2 20 2]])) 287 | 288 | ;; 289 | 290 | (defn render-label 291 | [label ^long w] 292 | (let [ww (int (* 0.95 w)) 293 | sx (/ (- w ww) 2)] 294 | (c2d/with-canvas-> (c2d/canvas w 12) 295 | (c2d/set-stroke 0.5) 296 | (c2d/filled-with-stroke (c/color :white 150) (c/color :black 100) c2d/rect sx 1 ww 10) 297 | (c2d/set-font-attributes 10) 298 | (c2d/text label (/ w 2) 10 :center)))) 299 | 300 | ;; 301 | 302 | (defn label-size 303 | ([s] (label-size s {})) 304 | ([s {:keys [font font-size ^double margin] :or {margin 8}}] 305 | (c2d/with-canvas [c (c2d/canvas 1 1)] 306 | (when font (c2d/set-font c font)) 307 | (when font-size (c2d/set-font-attributes c font-size)) 308 | (let [[x ^double y _ h] (c2d/text-bounding-box c s)] 309 | {:shift-y (/ margin 2) 310 | :block-size (+ margin (m/ceil h)) 311 | :pos [x (m/floor (- y))]})))) 312 | 313 | ;; ;;;;;;;;;; 314 | 315 | (defonce configuration (atom {})) 316 | 317 | (defn- inherite-configuration 318 | [inheritance] 319 | (reduce (fn [conf k] 320 | (if (contains? @configuration k) 321 | (deep-merge conf @(@configuration k)) 322 | conf)) {} inheritance)) 323 | 324 | (defn register-configuration! 325 | [chart config-map & inheritance] 326 | (swap! configuration assoc chart (delay (deep-merge (inherite-configuration inheritance) config-map)))) 327 | 328 | #_(register-configuration! :abc {:stroke {:size 3 :line 123}}) 329 | #_(register-configuration! :ded {:color :black} :abc :abc) 330 | #_(register-configuration! :vvv {:stroke {:size 10}} :ded :abc) 331 | 332 | 333 | 334 | ;; 335 | 336 | (defn read-json [f] (with-open [reader (io/reader f)] 337 | (doall (json/read-json reader true)))) 338 | 339 | 340 | (defn read-csv [f] (rest (with-open [reader (io/reader f)] 341 | (doall (csv/read-csv reader))))) 342 | 343 | (m/unuse-primitive-operators) 344 | -------------------------------------------------------------------------------- /src/cljplot/core.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.core 2 | (:require [clojure2d.core :refer [next-filename]] 3 | [clojure2d.extra.utils :as utils] 4 | [cljplot.impl.histogram] 5 | [cljplot.build :as b] 6 | [cljplot.render :as r] 7 | [cljplot.impl.strips] 8 | [cljplot.impl.scatter] 9 | [cljplot.impl.line] 10 | [cljplot.impl.heatmap] 11 | [cljplot.impl.label] 12 | [cljplot.impl.math] 13 | [cljplot.impl.free] 14 | [cljplot.impl.time-series])) 15 | 16 | (defn save 17 | "Save `chart`." 18 | ([chart name] 19 | (clojure2d.core/save chart name)) 20 | ([chart] 21 | (clojure2d.core/save chart (next-filename "charts/" ".png")))) 22 | 23 | (def show utils/show-image) 24 | 25 | ;; 26 | 27 | (defmacro xy-chart 28 | [conf series & mods] 29 | `(-> ~series 30 | (b/preprocess-series) 31 | ~@mods 32 | (r/render-lattice ~conf))) 33 | -------------------------------------------------------------------------------- /src/cljplot/impl/free.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.impl.free 2 | (:require [cljplot.common :as common])) 3 | 4 | (defmethod common/data-extent :free [_ _ _] nil) 5 | 6 | (defmethod common/render-graph :free [_ draw conf {:keys [orientation] :as chart-conf}] 7 | (common/do-graph (assoc chart-conf 8 | :oversize 0 9 | :orientation (or orientation :bottom)) false (draw c conf chart-conf))) 10 | -------------------------------------------------------------------------------- /src/cljplot/impl/heatmap.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.impl.heatmap 2 | (:require [cljplot.common :as common] 3 | [clojure2d.core :as c2d] 4 | [clojure2d.pixels :as p] 5 | [fastmath.core :as m] 6 | [fastmath.stats :as stats] 7 | [fastmath.grid :as grid] 8 | [fastmath.vector :as v] 9 | [clojure2d.color :as c])) 10 | 11 | (set! *warn-on-reflection* true) 12 | (set! *unchecked-math* :warn-on-boxed) 13 | (m/use-primitive-operators) 14 | 15 | (defmethod common/render-graph :cloud [_ data {:keys [kernel kernel-params] :as conf} {:keys [x y ^int w ^int h] :as chart-data}] 16 | (let [grad (if kernel 17 | (if kernel-params 18 | (p/gradient-renderer w h kernel kernel-params) 19 | (p/gradient-renderer w h kernel)) 20 | (p/gradient-renderer w h)) 21 | scale-x (:scale x) 22 | scale-y (:scale y)] 23 | (common/do-graph chart-data false 24 | 25 | (doseq [[x y] data] 26 | (p/add-pixel! grad (* w ^double (scale-x x)) (* h ^double (scale-y y)))) 27 | 28 | (let [p (p/to-pixels grad conf)] 29 | (c2d/image c (c2d/get-image p) 0 0))))) 30 | 31 | (defn- calc-bheatmap 32 | [data g sx sy] 33 | (reduce (fn [m [x y cnt]] 34 | (if-not (and x y) 35 | m 36 | (let [cnt (or cnt 1) 37 | cell (grid/coords->mid g (v/vec2 (sx x) (sy y)))] 38 | (if (contains? m cell) 39 | (update m cell clojure.core/+ cnt) 40 | (assoc m cell cnt))))) {} data)) 41 | 42 | (defmethod common/render-graph :binned-heatmap [_ data {:keys [grid size gradient ^double alpha-factor]} {:keys [x y ^int w ^int h] :as chart-data}] 43 | (let [scale-x (partial (:scale x) 0 w) 44 | scale-y (partial (:scale y) 0 h) 45 | grid (grid/grid grid size) 46 | data (calc-bheatmap data grid scale-x scale-y) 47 | [mnz mxz] (stats/extent (vals data)) 48 | gradient (if (pos? alpha-factor) 49 | (fn [v] (let [id (m/norm v mnz mxz)] 50 | (c/set-alpha (gradient id) (* 255.0 (m/pow id alpha-factor))))) 51 | (fn [v] (gradient (m/norm v mnz mxz))))] 52 | (common/do-graph (assoc chart-data :oversize 0) false 53 | 54 | (doseq [[[x y] v] data] 55 | (c2d/set-color c (gradient v)) 56 | (c2d/grid-cell c grid x y))))) 57 | 58 | ;; 59 | 60 | (defmethod common/prepare-data :heatmap [_ data _] 61 | (if (map? data) 62 | data 63 | (into {} data))) 64 | 65 | (defmethod common/data-extent :heatmap [_ data _] 66 | (let [ks (keys data)] 67 | {:x [:categorical (sort (distinct (map first ks)))] 68 | :y [:categorical (sort (comp clojure.core/- compare) (distinct (map second ks)))] 69 | :z [:numerical (butlast (stats/extent (vals data)))]})) 70 | 71 | (defn- pos->rect 72 | [{:keys [^double start ^double end ^double point]} ^long size] 73 | (let [s (* start size)] 74 | [s (max 1 (m/ceil (+ 0.5 (- (* end size) s)))) (m/round (* point size))])) 75 | 76 | (defmethod common/render-graph :heatmap [_ data {:keys [gradient extent annotate? annotate-fmt]} {:keys [x y ^int w ^int h] :as chart-data}] 77 | (let [scale-x (:scale x) 78 | scale-y (:scale y) 79 | [mnz mxz] (second (:z extent)) 80 | grad (comp gradient #(m/norm % mnz mxz)) 81 | fmt (common/coerce-format-fn annotate-fmt)] 82 | (common/do-graph chart-data false 83 | (c2d/set-font-attributes c 8) 84 | (doseq [[[x y] v] (sort-by first data) 85 | :let [[xx wx px] (pos->rect (scale-x x) w) 86 | [yy hy py] (pos->rect (scale-y y) h) 87 | col (grad v)]] 88 | (-> c 89 | (c2d/set-color col) 90 | (c2d/rect xx yy wx hy)) 91 | (when annotate? 92 | (-> c 93 | (c2d/set-color (if (< (c/contrast-ratio col :black) 6.0) :white :black)) 94 | (common/transformed-text (fmt v) px py :center))))))) 95 | 96 | (m/unuse-primitive-operators) 97 | -------------------------------------------------------------------------------- /src/cljplot/impl/histogram.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.impl.histogram 2 | (:require [cljplot.common :as common] 3 | [cljplot.scale :as s] 4 | [fastmath.core :as m] 5 | [fastmath.stats :as stats] 6 | [clojure2d.core :as c2d] 7 | [clojure2d.color :as c])) 8 | 9 | (set! *warn-on-reflection* true) 10 | (set! *unchecked-math* :warn-on-boxed) 11 | (m/use-primitive-operators) 12 | 13 | #_(register-configuration! :histogram {:color blue 14 | :palette (cycle (c/palette-presets :category20)) 15 | :stroke stroke-common 16 | :percents? true 17 | :stroke? true 18 | :type :bars 19 | :padding-in 0.1 20 | :padding-out 0.2 21 | :bins nil 22 | :margins {:x [0.05 0.05] :y [0.0 0.01]}}) 23 | 24 | 25 | (defmethod common/prepare-data :frequencies [_ data {:keys [pmf?]}] 26 | (let [s? (sequential? (first data)) 27 | data (if s? data [data]) 28 | freqs (mapv frequencies data)] 29 | (if-not pmf? 30 | freqs 31 | (let [sums (mapv #(reduce m/+ 0.0 (vals %)) freqs)] 32 | (map (fn [freq ^double s] 33 | (common/map-kv #(/ ^double % s) freq)) freqs sums))))) 34 | 35 | (defmethod common/data-extent :frequencies [_ data {:keys [range? sort?]}] 36 | (let [ks (->> data 37 | (map keys) 38 | (flatten) 39 | (distinct)) 40 | n? (every? integer? ks)] 41 | {:x [:categorical (if (and n? range?) 42 | (map int (range (reduce m/min ks) (inc ^int (reduce m/max ks)))) 43 | (if sort? (sort ks) ks))] 44 | :y [:numerical [0 (->> data 45 | (map vals) 46 | (flatten) 47 | (reduce m/max))]]})) 48 | 49 | (defn- histogram-density 50 | [{:keys [^long samples ^double step] :as h} density?] 51 | (let [f (case density? 52 | :pmf (/ 1.0 samples) 53 | :absolute (/ step) 54 | (/ (* step samples)))] 55 | (update h :bins (partial map (fn [[x ^long s]] [x (* s f)]))))) 56 | 57 | (defn- cumulate 58 | [{:keys [bins ^double step] :as h} density?] 59 | (let [b (reductions m/+ (map second bins)) 60 | step (if (or (not density?) (= :pmf density?)) 1.0 step)] 61 | (update h :bins (partial map (fn [^double c [x _]] [x (* step c)]) b)))) 62 | 63 | (defmethod common/prepare-data :histogram [_ data {:keys [bins density? cumulative?]}] 64 | (let [s? (sequential? (first data)) 65 | fd (if s? (flatten data) data) 66 | b (stats/estimate-bins fd bins) 67 | e (stats/extent fd) 68 | hs (map #(cond-> (stats/histogram % b e) 69 | density? (histogram-density density?) 70 | cumulative? (cumulate density?)) 71 | (if s? data [data]))] 72 | (-> (select-keys (first hs) [:min :max :step]) 73 | (assoc :bins (map :bins hs))))) 74 | 75 | (defmethod common/data-extent :histogram [_ data _] 76 | (let [d (map (partial map second) (:bins data)) 77 | max-bin (reduce m/max (flatten d)) 78 | ^double mn (:min data) 79 | ^double mx (:max data) 80 | diff (- mx mn)] 81 | {:x [:numerical [(if (< diff 2.0) mn (m/floor mn)) 82 | (if (< diff 2.0) mx (m/ceil mx))]] 83 | :y [:numerical [0 max-bin]]})) 84 | 85 | (defn- draw-series 86 | [canvas data {:keys [palette stroke stroke? type padding-in padding-out ^double zero] 87 | :or {type :bars}}] 88 | (let [bands (s/bands {:padding-out padding-out :padding-in padding-in} (count data)) 89 | zero (+ zero 3)] 90 | (doseq [[idx d] (map-indexed vector data)] 91 | (let [{:keys [^double start ^double end ^double point]} (bands idx) 92 | col (nth palette idx)] 93 | (doseq [[^double x1 ^double x2 ^double y] d 94 | :let [diff (- x2 x1) 95 | startx (+ x1 (* diff start)) 96 | endx (+ x1 (* diff end)) 97 | pointx (+ x1 (* diff point)) 98 | diffx (- endx startx) 99 | diffy (max 0.0 (- y zero))]] 100 | (case type 101 | :lollipops (-> canvas 102 | (c2d/set-color col) 103 | (c2d/set-stroke-custom stroke) 104 | (c2d/line pointx zero pointx y) 105 | (c2d/ellipse pointx y diffx diffx)) 106 | (if stroke? 107 | (-> canvas 108 | (c2d/set-stroke-custom stroke) 109 | (c2d/filled-with-stroke col (c/darken col) c2d/rect startx zero diffx diffy)) 110 | (-> canvas 111 | (c2d/set-color col) 112 | (c2d/rect startx zero diffx diffy))))))))) 113 | 114 | (defmethod common/render-graph :frequencies [_ data conf {:keys [^int w h x y] :as chart-data}] 115 | (let [sx (:scale x) 116 | scale-y (partial (:scale y) 0 h) 117 | d (map (partial map (fn [[x y]] 118 | (let [{:keys [^double start ^double end]} (sx x) 119 | s (* start w) 120 | e (* end w)] 121 | [s e (scale-y y)]))) data)] 122 | (common/do-graph chart-data false 123 | (draw-series c d (assoc conf :zero (scale-y 0.0)))))) 124 | 125 | (defmethod common/render-graph :histogram [_ {:keys [^double step bins]} conf {:keys [w h x y] :as chart-data}] 126 | (let [scale-x (partial (:scale x) 0 w) 127 | scale-y (partial (:scale y) 0 h) 128 | d (map (partial map (fn [[^double x y]] [(scale-x x) (scale-x (+ x step)) (scale-y y)])) bins)] 129 | (common/do-graph chart-data false 130 | (draw-series c d (assoc conf :zero (scale-y 0.0)))))) 131 | 132 | (m/unuse-primitive-operators) 133 | -------------------------------------------------------------------------------- /src/cljplot/impl/label.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.impl.label 2 | (:require [cljplot.common :as common] 3 | [clojure2d.core :as c2d] 4 | [fastmath.core :as m])) 5 | 6 | (set! *warn-on-reflection* true) 7 | (set! *unchecked-math* :warn-on-boxed) 8 | (m/use-primitive-operators) 9 | 10 | (defmethod common/data-extent :label [_ _ _] nil) 11 | (defmethod common/prepare-data :label [_ s conf] 12 | (assoc (common/label-size s conf) :s s :conf conf)) 13 | 14 | (defmethod common/render-graph :label [_ {:keys [s pos shift-y]} {:keys [font font-size font-style color]} {:keys [^int w ^int h orientation] :as chart-data}] 15 | (let [fix-orientation (assoc chart-data :orientation (case orientation 16 | :left :right 17 | :top :bottom 18 | orientation))] 19 | (common/do-graph fix-orientation false 20 | (when font (c2d/set-font c font)) 21 | (when font-size 22 | (if font-style 23 | (c2d/set-font-attributes c font-size font-style) 24 | (c2d/set-font-attributes c font-size))) 25 | 26 | (when (= orientation :right) 27 | (-> c 28 | (c2d/translate (/ w 2) (/ h 2)) 29 | (c2d/rotate m/PI) 30 | (c2d/translate (- (/ w 2)) (- (/ h 2))))) 31 | (-> c 32 | (c2d/translate (/ w 2) shift-y) 33 | (c2d/translate pos) 34 | (c2d/set-color color) 35 | (c2d/text s 0 0 :center))))) 36 | 37 | (m/unuse-primitive-operators) 38 | -------------------------------------------------------------------------------- /src/cljplot/impl/line.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.impl.line 2 | (:require [clojure2d.core :as c2d] 3 | [fastmath.core :as m] 4 | [clojure2d.color :as c] 5 | [cljplot.common :as common] 6 | [fastmath.interpolation.linear :as li] 7 | [fastmath.stats :as stats] 8 | [fastmath.kernel :as k] 9 | [fastmath.random :as r])) 10 | 11 | (set! *warn-on-reflection* true) 12 | (set! *unchecked-math* :warn-on-boxed) 13 | (m/use-primitive-operators) 14 | 15 | (defn- process-interpolation 16 | [data interpolation x w] 17 | (if (fn? interpolation) 18 | (let [sampled-values (m/sample (:inverse (:scale x)) 0.0 1.0 (/ ^int w 2) false) 19 | i (common/wrap-interpolator-for-dt interpolation (:domain x) (map first data) (map second data))] 20 | (map #(vector % (i %)) sampled-values)) 21 | data)) 22 | 23 | ;; TODO: move interpolation to the prepare-data phase (like in sarea) 24 | 25 | (defn- split-at-invalid-double 26 | [xs] 27 | (loop [s xs 28 | buff []] 29 | (if-not (seq s) 30 | buff 31 | (let [[v inv] (split-with (comp m/valid-double? second) s)] 32 | (recur (drop-while (comp m/invalid-double? second) inv) 33 | (if (seq v) (conj buff v) buff)))))) 34 | 35 | (defmethod common/render-graph :line [_ data {:keys [color stroke interpolation smooth? area? point] :as conf} 36 | {:keys [w h x y] :as chart-data}] 37 | (let [scale-x (partial (:scale x) 0 w) 38 | scale-y (partial (:scale y) 0 h) 39 | data (map #(process-interpolation % interpolation x w) (split-at-invalid-double data)) 40 | pfn (if (and smooth? (not area?)) c2d/path-bezier c2d/path) 41 | lcolor (if area? (c/darken color) color) 42 | ps (map #(map (juxt (comp scale-x first) (comp scale-y second)) %) data)] 43 | (common/do-graph (assoc chart-data :oversize 0) true 44 | #_(#{\o \O} (:type point)) 45 | (doseq [p ps] 46 | (when area? 47 | (c2d/set-color c color) 48 | (pfn c (conj (vec (conj p [0.0 0.0])) [w 0.0]) true false)) 49 | (-> c 50 | (c2d/set-color lcolor) 51 | (c2d/set-stroke-custom stroke) 52 | (pfn p)) 53 | 54 | (when-let [point-type (:type point)] 55 | (let [size-fn (:size point) 56 | stroke (:stroke point)] 57 | (doseq [[x y :as dta] p 58 | :let [size (size-fn dta conf)]] 59 | (common/draw-shape c x y point-type (or (:color point) color) stroke size)))))))) 60 | 61 | ;; 62 | 63 | (defmethod common/render-graph :area [_ data conf chart-data] 64 | (common/render-graph :line data (assoc conf :area? true) chart-data)) 65 | 66 | ;; 67 | 68 | (defmethod common/data-extent :ci [_ [top bottom] _] (common/common-extent (concat top bottom))) 69 | (defmethod common/render-graph :ci [_ [top bottom] {:keys [color stroke interpolation point smooth?]} 70 | {:keys [w h x y] :as chart-data}] 71 | (let [scale-x (partial (:scale x) 0 w) 72 | scale-y (partial (:scale y) 0 h) 73 | data-top (process-interpolation top interpolation x w) 74 | data-bottom (process-interpolation bottom interpolation x w) 75 | p-top (map (juxt (comp scale-x first) (comp scale-y second)) data-top) 76 | p-bottom (map (juxt (comp scale-x first) (comp scale-y second)) data-bottom) 77 | pfn (if smooth? c2d/path-bezier c2d/path)] 78 | (common/do-graph chart-data (#{\o \O} point) 79 | (-> c 80 | (c2d/set-color color) 81 | (pfn (concat p-top (reverse p-bottom)) true false)) 82 | (when stroke 83 | (-> c 84 | (c2d/set-color (c/darken color)) 85 | (c2d/set-stroke-custom stroke) 86 | (pfn p-top) 87 | (pfn p-bottom)))))) 88 | ;; 89 | 90 | (defmethod common/prepare-data :function [_ function {:keys [samples domain]}] 91 | (let [[mx my] domain] 92 | (m/sample function mx my (or samples 100) true))) 93 | 94 | (defmethod common/data-extent :function [_ sampled {:keys [domain]}] 95 | {:x [:numerical domain] :y (common/extent (map second sampled))}) 96 | 97 | (defmethod common/render-graph :function [_ sampled conf chart-data] 98 | (common/render-graph :line sampled conf chart-data)) 99 | 100 | ;; 101 | 102 | (defmethod common/prepare-data :density [_ data {:keys [kernel-bandwidth kernel-type margins] 103 | :or {kernel-type :gaussian} 104 | :as conf}] 105 | (let [dens-data (common/extract-first data) 106 | f (if kernel-bandwidth 107 | (k/kernel-density kernel-type dens-data kernel-bandwidth) 108 | (k/kernel-density kernel-type dens-data)) 109 | with-domain (assoc conf :domain (common/extend-domain-numerical (take 2 (stats/extent dens-data)) (or (:x margins) [0 0])))] 110 | [with-domain (common/prepare-data :function f with-domain)])) 111 | 112 | (defmethod common/data-extent :density [_ [with-domain data] _] (common/data-extent :function data with-domain)) 113 | (defmethod common/render-graph :density [_ [with-domain data] _ graph-conf] (common/render-graph :function data with-domain graph-conf)) 114 | 115 | ;; 116 | 117 | (defmethod common/prepare-data :cdf [_ data conf] 118 | (if (r/distribution? data) 119 | [conf (common/prepare-data :function (partial r/cdf data) conf)] 120 | (let [data (common/extract-first data) 121 | domain (take 2 (stats/extent data)) 122 | f (partial r/cdf (r/distribution :real-discrete-distribution {:data data})) 123 | with-domain (assoc conf :domain domain)] 124 | [with-domain (common/prepare-data :function f with-domain)]))) 125 | 126 | (defmethod common/data-extent :cdf [_ [with-domain data] _] (common/data-extent :function data with-domain)) 127 | (defmethod common/render-graph :cdf [_ [with-domain data] _ graph-conf] (common/render-graph :function data with-domain graph-conf)) 128 | 129 | ;; 130 | 131 | (defn- sarea-map 132 | [f vs] 133 | (mapv (fn [[x ys]] 134 | (let [l (last ys)] 135 | [x (mapv (partial f l) ys)])) vs)) 136 | 137 | (defn- sarea-normalized [vs] (sarea-map #(m/norm %2 0 %1) vs)) 138 | (defn- sarea-stream [vs] (sarea-map #(let [hl (/ ^int %1 2)] (m/norm %2 0 %1 (- hl) hl)) vs)) 139 | 140 | (defmethod common/prepare-data :sarea [_ data {:keys [interpolation method]}] 141 | (let [xs (->> (map second data) 142 | (mapcat (partial map first)) 143 | (distinct) 144 | (sort)) 145 | ks (mapv first data) 146 | domain [(first xs) (last xs)] 147 | interp (or interpolation li/linear) 148 | data-as-map (if (map? data) data (into {} data)) 149 | interpolators (apply juxt 150 | (constantly 0) 151 | (map (common/map-kv #(common/wrap-interpolator-for-dt interp domain (map first %) (map second %)) data-as-map) ks)) 152 | vs (mapv #(vector % (reductions m/+ (interpolators %))) xs) 153 | ^double maxv (reduce m/max (mapv (comp last second) vs))] 154 | (case method 155 | :normalized [domain [0.0 1.0] ks (sarea-normalized vs)] 156 | :stream [domain [(- (/ maxv 2)) (/ maxv 2)] ks (sarea-stream vs)] 157 | [domain [0 maxv] ks vs]))) 158 | 159 | (defmethod common/data-extent :sarea [_ [x y] _] 160 | {:x [(if (common/date-time? (first x)) :temporal :numerical) x] 161 | :y [:numerical y]}) 162 | 163 | (defmethod common/render-graph :sarea [_ [_ _ ks vs] {:keys [palette]} {:keys [w h x y] :as chart-data}] 164 | (let [scale-x (partial (:scale x) 0 w) 165 | scale-y (partial (:scale y) 0 h) 166 | xs (mapv scale-x (map first vs)) 167 | ys (mapv second vs) 168 | ys (map #(mapv (fn [x y] [x (scale-y (nth y %))]) xs ys) (range (inc (count ks)))) 169 | ps (map (fn [[p1 p2]] (concat p1 (reverse p2))) (partition 2 1 ys))] 170 | (common/do-graph chart-data false 171 | (c2d/set-color c :black) 172 | (doseq [[col p] (map vector palette ps)] 173 | (c2d/set-color c col) 174 | (c2d/path c p true false))))) 175 | 176 | ;; lines 177 | 178 | (defmethod common/data-extent :abline [_ _ _] nil) 179 | (defmethod common/render-graph :abline [_ [a b x1 x2] {:keys [color] :as conf} {:keys [w h x y extent] :as chart-data}] 180 | (let [scale-x (partial (:scale x) 0 w) 181 | scale-y (partial (:scale y) 0 h) 182 | ^double a (or a 1.0) 183 | ^double b (or b 0.0) 184 | [mnx mxx] (:x extent) 185 | ^double x1 (or x1 mnx) 186 | ^double x2 (or x2 mxx) 187 | y1 (+ b (* a x1)) 188 | y2 (+ b (* a x2))] 189 | (common/do-graph (assoc chart-data :oversize 0) false 190 | (-> (c2d/set-color c color) 191 | (c2d/set-stroke-custom conf) 192 | (c2d/line (scale-x x1) (scale-y y1) (scale-x x2) (scale-y y2)))))) 193 | 194 | (defmethod common/data-extent :vline [_ _ _] nil) 195 | (defmethod common/render-graph :vline [_ xx {:keys [color] :as conf} {:keys [w ^int h x] :as chart-data}] 196 | (let [xx ((:scale x) 0 w (or xx 0.0))] 197 | (common/do-graph (assoc chart-data :oversize 0) false 198 | (-> (c2d/set-color c color) 199 | (c2d/set-stroke-custom conf) 200 | (c2d/line xx 0 xx (dec h)))))) 201 | 202 | (defmethod common/data-extent :hline [_ _ _] nil) 203 | (defmethod common/render-graph :hline [_ yy {:keys [color] :as conf} {:keys [^int w h y] :as chart-data}] 204 | (let [yy ((:scale y) 0 h (or yy 0.0))] 205 | (common/do-graph (assoc chart-data :oversize 0) false 206 | (-> (c2d/set-color c color) 207 | (c2d/set-stroke-custom conf) 208 | (c2d/line 0 yy (dec w) yy))))) 209 | 210 | (m/unuse-primitive-operators) 211 | -------------------------------------------------------------------------------- /src/cljplot/impl/math.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.impl.math 2 | (:require [cljplot.common :as common] 3 | [fastmath.core :as m] 4 | [fastmath.vector :as v] 5 | [clojure2d.color :as c] 6 | [fastmath.complex :as cx] 7 | [fastmath.random :as r] 8 | [fastmath.fields :as f] 9 | [clojure2d.core :as c2d] 10 | [fastmath.grid :as grid] 11 | [fastmath.stats :as stats] 12 | [cljplot.scale :as s]) 13 | (:import [marchingsquares Algorithm])) 14 | 15 | (set! *warn-on-reflection* true) 16 | (set! *unchecked-math* :warn-on-boxed) 17 | (m/use-primitive-operators) 18 | 19 | (def ^:private pi-r [m/-PI m/PI]) 20 | 21 | (defmethod common/data-extent :complex [_ _ {:keys [x y]}] 22 | {:x [:numerical (or x pi-r)] 23 | :y [:numerical (or y pi-r)]}) 24 | 25 | (defmacro ^:private permutation->color 26 | [p a b c] 27 | `(case ~p 28 | 0 (c/color ~a ~b ~c) 29 | 1 (c/color ~a ~c ~b) 30 | 2 (c/color ~b ~a ~c) 31 | 3 (c/color ~b ~c ~a) 32 | 4 (c/color ~c ~a ~b) 33 | 5 (c/color ~c ~b ~a) 34 | (c/color ~a ~b ~c))) 35 | 36 | (defn- wrap 37 | ^double [method ^double v] 38 | (case method 39 | :log2 (m/frac (m/log2 (inc v))) 40 | :log10 (m/frac (m/log10 (inc v))) 41 | :sin (m/norm (m/sin v) -1.0 1.0 0.0 1.0) 42 | :exp (- 1.0 (m/exp (- v))) 43 | :sigmoid (m/sigmoid v) 44 | (m/frac v))) 45 | 46 | (defmethod common/render-graph :complex [_ f {:keys [colorspace permutation wrap-method]} {:keys [w h x y] :as chart-data}] 47 | (let [permutation (int permutation) 48 | iscale-x (:inverse (:scale x)) 49 | iscale-y (:inverse (:scale y)) 50 | dw (double w) 51 | dh (double h) 52 | from-cs (or (second (c/colorspaces* colorspace)) c/from-HSB*)] 53 | 54 | (common/do-graph chart-data false 55 | (dotimes [x w] 56 | (dotimes [y h] 57 | (let [xx (/ x dw) 58 | yy (/ y dh) 59 | sx (iscale-x xx) 60 | sy (iscale-y yy) 61 | fv (f (v/vec2 sx sy)) 62 | angle (m/norm (cx/arg fv) m/-PI m/PI 0.0 255.0) 63 | mag (cx/abs fv) 64 | mag (* 255.0 (wrap wrap-method mag)) 65 | col (from-cs (permutation->color permutation angle (- 255.0 (/ (- 255.0 mag) 4.0)) mag))] 66 | (c2d/set-color c col) 67 | (c2d/rect c x y 1 1))))))) 68 | 69 | ;; scalar 70 | 71 | (defmethod common/data-extent :scalar [_ d c] (common/data-extent :complex d c)) 72 | 73 | (defmethod common/render-graph :scalar [_ f {:keys [gradient wrap-method]} {:keys [w h x y] :as chart-data}] 74 | (let [iscale-x (:inverse (:scale x)) 75 | iscale-y (:inverse (:scale y)) 76 | dw (double w) 77 | dh (double h)] 78 | 79 | (common/do-graph chart-data false 80 | (dotimes [x w] 81 | (dotimes [y h] 82 | (let [xx (/ x dw) 83 | yy (/ y dh) 84 | sx (iscale-x xx) 85 | sy (iscale-y yy) 86 | v (wrap wrap-method (f (v/vec2 sx sy)))] 87 | (c2d/set-color c (gradient v)) 88 | (c2d/rect c x y 1 1))))))) 89 | 90 | ;; 91 | 92 | (defmethod common/data-extent :function-2d [_ d c] (common/data-extent :complex d c)) 93 | 94 | (defmethod common/render-graph :function-2d [_ f {:keys [gradient]} {:keys [^int w ^int h x y] :as chart-data}] 95 | (let [iscale-x (:inverse (:scale x)) 96 | iscale-y (:inverse (:scale y)) 97 | dw (double w) 98 | dh (double h) 99 | buffer (double-array (* w h))] 100 | 101 | (dotimes [y h] 102 | (let [off (* y w)] 103 | (dotimes [x w] 104 | (let [xx (/ x dw) 105 | yy (/ y dh) 106 | ^double v (f (iscale-x xx) (iscale-y yy))] 107 | (aset buffer (+ off x) v))))) 108 | 109 | (let [[mnz mxz] (stats/extent buffer)] 110 | (common/do-graph chart-data false 111 | (dotimes [y h] 112 | (let [off (* y w)] 113 | (dotimes [x w] 114 | (let [v (aget buffer (+ off x))] 115 | (c2d/set-color c (gradient (m/norm v mnz mxz))) 116 | (c2d/rect c x y 1 1))))))))) 117 | 118 | 119 | ;; contour 120 | 121 | (defmethod common/data-extent :contour-2d [_ d c] (common/data-extent :complex d c)) 122 | 123 | (defmethod common/render-graph :contour-2d [_ f {:keys [palette ^int contours fill?]} {:keys [^int w ^int h x y] :as chart-data}] 124 | (let [palette (c/resample palette (inc contours)) 125 | iscale-x (:inverse (:scale x)) 126 | iscale-y (:inverse (:scale y)) 127 | dw (double w) 128 | dh (double h) 129 | values (for [^long y (range h) 130 | ^long x (range w) 131 | :let [xx (/ x dw) 132 | yy (/ y dh)]] 133 | (f (iscale-x xx) (iscale-y yy))) 134 | ^Algorithm algo (Algorithm. (m/seq->double-double-array (partition (int w) values))) 135 | steps (s/splice-range (inc contours) (.-min algo) (.-max algo))] 136 | (common/do-graph chart-data true 137 | (doseq [[id p] (map-indexed vector (.buildContours algo (double-array steps))) 138 | :let [col (nth palette id)]] 139 | (if fill? 140 | (do 141 | (c2d/set-color c col) 142 | (.fill ^java.awt.Graphics2D (.graphics ^clojure2d.core.Canvas c) p) 143 | (c2d/set-color c (c/darken col)) 144 | (.draw ^java.awt.Graphics2D (.graphics ^clojure2d.core.Canvas c) p)) 145 | (do 146 | (c2d/set-color c :black 200) 147 | (.draw ^java.awt.Graphics2D (.graphics ^clojure2d.core.Canvas c) p))))))) 148 | 149 | 150 | ;; field 151 | 152 | (defmethod common/prepare-data :field [_ f {:keys [x y points generator jitter wrap?]}] 153 | (let [[x1 x2] (or x pi-r) 154 | [y1 y2] (or y pi-r) 155 | f (if wrap? (comp (f/field :sinusoidal ) f) f)] 156 | (mapv (fn [[xx yy]] (f (v/vec2 (m/norm xx 0.0 1.0 x1 x2) 157 | (m/norm yy 0.0 1.0 y1 y2)))) (take points (r/jittered-sequence-generator generator 2 jitter))))) 158 | 159 | (defmethod common/render-graph :field [_ data {:keys [color]} {:keys [^int w ^int h x y] :as chart-data}] 160 | (let [scale-x (:scale x) 161 | scale-y (:scale y)] 162 | 163 | (common/do-graph chart-data false 164 | (c2d/set-color c color) 165 | (doseq [[xx yy] data] 166 | (c2d/rect c (* w ^double (scale-x xx)) (* h ^double (scale-y yy)) 1 1))))) 167 | 168 | ;; vectors 169 | 170 | (defmethod common/data-extent :vector [_ f c] (common/data-extent :complex f c)) 171 | 172 | (defmethod common/render-graph :vector [_ f {:keys [^double size grid color ^double scale]} {:keys [^int w ^int h x y] :as chart-data}] 173 | (let [scale-x (:scale x) 174 | scale-y (:scale y) 175 | iscale-x (:inverse scale-x) 176 | iscale-y (:inverse scale-y) 177 | grid (grid/grid grid size) 178 | hsize (/ size 2.0) 179 | coords (distinct (for [x (range 0 w hsize) 180 | y (range 0 h hsize) 181 | :let [[^double mx ^double my] (grid/coords->mid grid [x y])]] 182 | [(iscale-x (/ mx w)) (iscale-y (/ my h))]))] 183 | 184 | (common/do-graph (assoc chart-data :oversize 0) true 185 | (c2d/set-color c color) 186 | (doseq [[x y] coords 187 | :let [xx (* w ^double (scale-x x)) 188 | yy (* h ^double (scale-y y)) 189 | v (f (v/vec2 x y)) 190 | len (* scale size (wrap :exp (v/mag v)))]] 191 | (-> c 192 | (c2d/push-matrix) 193 | (c2d/translate xx yy) 194 | (c2d/ellipse 0 0 3 3 false) 195 | (c2d/rotate (v/heading v)) 196 | (c2d/line 0 0 len 0)) 197 | (when (> len 2.0) 198 | (c2d/line c len 0 (- len 2.0) -2.0) 199 | (c2d/line c len 0 (- len 2.0) 2.0)) 200 | (c2d/pop-matrix c))))) 201 | 202 | ;; 203 | 204 | (defmethod common/prepare-data :trace [_ f {:keys [x y points generator jitter]}] 205 | (let [[x1 x2] (or x pi-r) 206 | [y1 y2] (or y pi-r)] 207 | [f (mapv (fn [[xx yy]] (v/vec2 (m/norm xx 0.0 1.0 x1 x2) 208 | (m/norm yy 0.0 1.0 y1 y2))) (take points (r/jittered-sequence-generator generator 2 jitter)))])) 209 | 210 | (defmethod common/data-extent :trace [_ data c] (common/data-extent :complex data c)) 211 | 212 | (defmethod common/render-graph :trace [_ [f coords] {:keys [^double step color ^double length]} {:keys [^int w ^int h x y] :as chart-data}] 213 | (let [scale-x (:scale x) 214 | scale-y (:scale y)] 215 | 216 | (common/do-graph (assoc chart-data :oversize 0) true 217 | (c2d/set-color c color) 218 | 219 | (doseq [v coords 220 | :let [p (take length 221 | (iterate (fn [v] 222 | (let [nv (f v)] 223 | (v/add v (v/mult nv (* (wrap :exp (v/mag nv)) step))))) v))]] 224 | (doseq [[x y] p] 225 | (c2d/point c (* w ^double (scale-x x)) (* h ^double (scale-y y)))))))) 226 | 227 | (m/unuse-primitive-operators) 228 | -------------------------------------------------------------------------------- /src/cljplot/impl/scatter.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.impl.scatter 2 | (:require [clojure2d.core :as c2d] 3 | [cljplot.common :as common] 4 | [cljplot.scale :as s] 5 | [fastmath.random :as r] 6 | [fastmath.core :as m] 7 | [clojure2d.pixels :as p] 8 | [clojure2d.color :as c]) 9 | (:import [clojure2d.java.filter Blur] 10 | [marchingsquares Algorithm])) 11 | 12 | (set! *warn-on-reflection* true) 13 | (set! *unchecked-math* :warn-on-boxed) 14 | (m/use-primitive-operators) 15 | 16 | (defmethod common/render-graph :scatter [_ data {:keys [color stroke size shape] :as conf} 17 | {:keys [w h x y] :as chart-data}] 18 | (let [scale-x (partial (:scale x) 0 w) 19 | scale-y (partial (:scale y) 0 h)] 20 | (common/do-graph chart-data (some #(#{\o \O} (shape % conf)) data) 21 | (let [coords (mapv (fn [[x y]] 22 | (c2d/transform c (scale-x x) (scale-y y))) data)] 23 | (c2d/reset-matrix c) 24 | (doseq [[v [tx ty]] (map vector data coords) 25 | :let [local-stroke (update stroke :size (:size stroke) v conf)]] 26 | (common/draw-shape c tx ty (shape v conf) (color v conf) local-stroke (size v conf))))))) 27 | 28 | (defmethod common/render-graph :bubble [_ data {:keys [size-range scale-z] :as conf} chart-data] 29 | (let [[mn mx] size-range 30 | z (:scale (s/scale-map scale-z {:domain (-> conf :extent :z second)})) 31 | size-fn (fn [[_ _ size] _] (z mn mx size))] 32 | (common/render-graph :scatter data (assoc conf :size size-fn) chart-data))) 33 | 34 | (defmethod common/render-graph :gbubble [_ data {:keys [cells grid-type] :as conf} {:keys [x y] :as chart-data}] 35 | (let [scale-x (:scale x) 36 | scale-y (:scale y) 37 | hd (common/heatmap-grid data scale-x scale-y grid-type (or cells 10)) 38 | z-extent (common/extent (map #(% 2) hd))] 39 | (common/render-graph :bubble hd (assoc-in conf [:extent :z] z-extent) chart-data))) 40 | 41 | ;; 42 | 43 | (defmethod common/prepare-data :qqplot [_ [d1 d2] {:keys [points] :or {points 100}}] 44 | (let [d1 (if (r/distribution? d1) d1 45 | (r/distribution :real-discrete-distribution {:data (common/extract-first d1)})) 46 | d2 (if (r/distribution? d2) d2 47 | (r/distribution :real-discrete-distribution {:data (common/extract-first d2)}))] 48 | (map #(let [v (m/norm % 0 points)] 49 | (vector (r/icdf d1 v) (r/icdf d2 v))) (range 1 points)))) 50 | 51 | (defmethod common/render-graph :qqplot [_ data conf graph-conf] (common/render-graph :scatter data conf graph-conf)) 52 | 53 | (defmethod common/prepare-data :normal-plot [_ data conf] (common/prepare-data :qqplot [(r/distribution :normal) data] conf)) 54 | (defmethod common/render-graph :normal-plot [_ data conf graph-conf] (common/render-graph :scatter data conf graph-conf)) 55 | 56 | (defmethod common/prepare-data :ppplot [_ [d1 d2] {:keys [^int points domain] :or {points 100}}] 57 | (let [[dx dy] (or domain [-1.0 1.0]) 58 | d1 (if (r/distribution? d1) d1 59 | (r/distribution :real-discrete-distribution {:data (common/extract-first d1)})) 60 | d2 (if (r/distribution? d2) d2 61 | (r/distribution :real-discrete-distribution {:data (common/extract-first d2)}))] 62 | (map #(let [v (m/norm % 0 points dx dy)] 63 | (vector (r/cdf d1 v) (r/cdf d2 v))) (range 0 (inc points))))) 64 | 65 | (defmethod common/render-graph :ppplot [_ data conf graph-conf] (common/render-graph :scatter data conf graph-conf)) 66 | 67 | ;; 68 | 69 | (defonce ^:private bw-gradient (c/gradient [:black :white])) 70 | 71 | (defmethod common/render-graph :density-2d [_ data {:keys [palette kernel kernel-params logarithmic? ^double blur-kernel-size ^int contours fill?]} {:keys [^int w ^int h x y] :as chart-data}] 72 | (let [palette (c/resample palette contours) 73 | scale-x (:scale x) 74 | scale-y (:scale y) 75 | g (if kernel 76 | (if kernel-params 77 | (p/gradient-renderer w h kernel kernel-params) 78 | (p/gradient-renderer w h kernel)) 79 | (p/gradient-renderer w h))] 80 | 81 | (doseq [[x y] data] 82 | (p/add-pixel! g (* w ^double (scale-x x)) (* h ^double (scale-y y)))) 83 | 84 | (let [g (->> (p/to-pixels g {:logarithmic? logarithmic? :gradient bw-gradient}) 85 | (map c/luma) 86 | (m/seq->double-array)) 87 | target (double-array (alength g))] 88 | 89 | (when (pos? blur-kernel-size) 90 | (Blur/gaussianBlur g target w h (if (< blur-kernel-size 1.0) (* 0.1 blur-kernel-size (max w h)) blur-kernel-size))) 91 | 92 | (let [^Algorithm algo (Algorithm. (m/seq->double-double-array (partition (int w) target))) 93 | steps (rest (s/splice-range (inc contours) (.-min algo) (.-max algo)))] 94 | (common/do-graph chart-data true 95 | (doseq [[id p] (map-indexed vector (.buildContours algo (double-array steps))) 96 | :let [col (nth palette id)]] 97 | (if fill? 98 | (do 99 | (c2d/set-color c col) 100 | (.fill ^java.awt.Graphics2D (.graphics ^clojure2d.core.Canvas c) p) 101 | (c2d/set-color c (c/darken col)) 102 | (.draw ^java.awt.Graphics2D (.graphics ^clojure2d.core.Canvas c) p)) 103 | (do 104 | (c2d/set-color c :black 200) 105 | (.draw ^java.awt.Graphics2D (.graphics ^clojure2d.core.Canvas c) p))))))))) 106 | 107 | (m/unuse-primitive-operators) 108 | -------------------------------------------------------------------------------- /src/cljplot/impl/time_series.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.impl.time-series 2 | (:require [clojure2d.core :as c2d] 3 | [cljplot.common :as common] 4 | [fastmath.stats :as stats] 5 | [fastmath.core :as m] 6 | [fastmath.random :as rnd])) 7 | 8 | (set! *warn-on-reflection* true) 9 | (set! *unchecked-math* :warn-on-boxed) 10 | (m/use-primitive-operators) 11 | 12 | (defmethod common/prepare-data :lag [_ data {:keys [lag]}] (map vector data (drop (or lag 1) data))) 13 | (defmethod common/render-graph :lag [_ data conf chart-data] (common/render-graph :scatter data conf chart-data)) 14 | 15 | (defn- ensure-vec 16 | [data] 17 | (if (vector? data) data (vec data))) 18 | 19 | ;; TODO move to fastmath 20 | 21 | (defn acf 22 | "Calculate acf for given number of lags" 23 | [data ^long lags] 24 | (let [vdata (ensure-vec data)] 25 | (mapv (fn [lag] 26 | (let [v2 (subvec vdata lag) 27 | v1 (subvec vdata 0 (count v2))] 28 | (stats/correlation v1 v2))) (range (inc lags))))) 29 | 30 | ;; http://feldman.faculty.pstat.ucsb.edu/174-03/lectures/l13 31 | (defn pacf 32 | [data ^long lags] 33 | (let [acf (acf data lags) 34 | phis (reductions (fn [curr ^long id] 35 | (let [phi (/ (- ^double (acf id) ^double (reduce m/+ (map-indexed #(* ^double (acf (dec (- id ^int %1))) ^double %2) curr))) 36 | (- 1.0 ^double (reduce m/+ (map-indexed #(* ^double (acf (inc ^int %1)) ^double %2) curr))))] 37 | (conj (mapv #(- ^double %1 (* phi ^double %2)) curr (reverse curr)) phi))) [(acf 1)] (range 2 (inc lags)))] 38 | (vec (conj (map last phis) 0.0)))) 39 | 40 | (defn- p-acf-data 41 | [method data lags] 42 | (let [vdata (ensure-vec data) 43 | cnt (count vdata) 44 | lags (or lags (min (dec cnt) (m/ceil (* 10.0 (m/log10 cnt))))) 45 | acf-fn (if (= method :acf) acf pacf) 46 | acf (map-indexed vector (acf-fn vdata lags)) 47 | rsqrt (/ 1.0 (m/sqrt cnt)) 48 | ci (* rsqrt ^double (rnd/icdf rnd/default-normal (* 0.5 (inc 0.95))))] 49 | (if (= method :acf) 50 | [acf rsqrt ci (mapv #(* ci (m/sqrt (dec (* 2.0 ^double %)))) 51 | (reductions (fn [^double acc ^double s] (+ acc (* s s))) (map second acf)))] 52 | [(rest acf) rsqrt ci]))) 53 | 54 | #_(last (p-acf-data :acf ma2 10)) 55 | 56 | ;; TODO move to test 57 | 58 | #_(def ep (repeatedly 10000 rnd/grand)) 59 | #_(def ma2 (take 500 (map (fn [e1 e2 e3] (+ (- e1) (* 0.8 e2) (* -0.9 e3))) (drop 2 ep) (drop 1 ep) ep))) 60 | 61 | #_ (mapv second (rest (first (p-acf-data :acf ma2 5)))) 62 | ;; => (-0.5860175473046139 0.28776310296448715 0.03196383068903399 0.007866082297411425 -0.08087093130708278) 63 | 64 | 65 | #_(let [rho (mapv second (first (p-acf-data :acf ma2 5))) 66 | rho1 (rho 1) 67 | rho2 (rho 2) 68 | phi11 rho1 69 | phi22 (/ (- rho2 (* phi11 rho1)) 70 | (- 1.0 (* phi11 rho1))) 71 | phi21 (- phi11 (* phi22 phi11)) 72 | rho3 (rho 3) 73 | phi33 (/ (- rho3 (* phi21 rho2) (* phi22 rho1)) 74 | (- 1.0 (* phi21 rho1) (* phi22 rho2))) 75 | phi31 (- phi21 (* phi33 phi22)) 76 | phi32 (- phi22 (* phi33 phi21)) 77 | rho4 (rho 4) 78 | phi44 (/ (- rho4 (* phi31 rho3) (* phi32 rho2) (* phi33 rho1)) 79 | (- 1.0 (* phi31 rho1) (* phi32 rho2) (* phi33 rho3)))] 80 | [phi22 phi33 phi44]) 81 | ;; => [-0.08476220976837147 0.25345653039561855 0.25255420956957964] 82 | 83 | 84 | #_ (mapv second (first (p-acf-data :pacf ma2 5))) 85 | 86 | 87 | (defmethod common/prepare-data :acf [_ data {:keys [lags]}] (p-acf-data :acf data lags)) 88 | 89 | (defmethod common/data-extent :acf [_ data _] 90 | (let [e (common/common-extent (first data)) 91 | [_ [^double mn mx]] (:y e)] 92 | (assoc-in e [:y 1] [(min 0.0 mn) mx]))) 93 | 94 | ;; pars: ci 0.95, color :red 95 | (defmethod common/render-graph :acf [_ [data ^double _rsqrt ^double ci0 cis] _conf {:keys [^int w ^int h x y] :as chart-data}] 96 | (let [scale-x (partial (:scale x) 0 w) 97 | scale-y (partial (:scale y) 0 h) 98 | zero (scale-y 0.0) 99 | w- (dec w) 100 | ^double ci- (scale-y (- ci0)) 101 | ^double ci (scale-y ci0)] 102 | (common/do-graph (assoc chart-data :oversize 0) false 103 | 104 | (c2d/set-color c :grey 80) 105 | 106 | (if cis 107 | (let [p1 (map-indexed #(vector (scale-x %1) (scale-y %2)) cis) 108 | p2 (reverse (map-indexed #(vector (scale-x %1) (scale-y (- ^double %2))) cis))] 109 | (c2d/path c (concat p2 p1) true false)) 110 | 111 | (c2d/rect c 0 ci- w (- ci ci-))) 112 | 113 | (-> c 114 | (c2d/set-color :black) 115 | (c2d/line 0 zero w- zero)) 116 | (doseq [[id [^double x ^double y]] (map-indexed vector data) 117 | :let [xx (scale-x x) 118 | yy (scale-y y)]] 119 | (c2d/set-color c :black) 120 | (c2d/line c xx zero xx yy) 121 | (when (or (and (not cis) (> (m/abs y) ci0)) 122 | (and cis (> (m/abs y) ^double (cis id)))) 123 | (c2d/set-color c :red)) 124 | (c2d/ellipse c xx yy 4 4))))) 125 | 126 | ;; pacf 127 | 128 | (defmethod common/prepare-data :pacf [_ data {:keys [lags]}] (p-acf-data :pacf data lags)) 129 | (defmethod common/data-extent :pacf [_ data conf] (common/data-extent :acf data conf)) 130 | (defmethod common/render-graph :pacf [_ data conf chart-data] (common/render-graph :acf data conf chart-data)) 131 | 132 | (m/unuse-primitive-operators) 133 | -------------------------------------------------------------------------------- /src/cljplot/render.clj: -------------------------------------------------------------------------------- 1 | (ns cljplot.render 2 | (:require [cljplot.scale :as s] 3 | [cljplot.common :as common] 4 | [cljplot.axis :as ax] 5 | [clojure2d.core :as c2d] 6 | [clojure2d.protocols :as p] 7 | [fastmath.core :as m] 8 | [fastmath.vector :as v])) 9 | 10 | (set! *warn-on-reflection* true) 11 | (set! *unchecked-math* :warn-on-boxed) 12 | (m/use-primitive-operators) 13 | 14 | (defn- get-pos-size 15 | "Sum sizes of all charts in given direction." 16 | [block] 17 | (reduce clojure.core/+ 0 (map :size block))) 18 | 19 | (defn- get-max-size 20 | [side] 21 | (reduce clojure.core/max 0 (map get-pos-size (vals side)))) 22 | 23 | (defmacro place-image 24 | [c canv anch px py] 25 | `(-> ~c 26 | (c2d/push-matrix) 27 | (c2d/translate ~anch) 28 | (c2d/image ~canv ~px ~py) 29 | (c2d/pop-matrix))) 30 | 31 | (defn- place-sides 32 | [c series scale [^int tx ^int ty] orientation axis bands] 33 | (let [x? (= :x axis)] 34 | (doseq [[pos srs] series 35 | :let [[start ssize] (bands pos) 36 | [imgx imgy] (if x? [start 0] [0 start])]] 37 | (c2d/push-matrix c) 38 | (doseq [{:keys [^double size series]} srs] 39 | (doseq [[t d conf] series 40 | :let [sx (scale pos) 41 | ;; construct y scale 42 | sy (or (:scale-y conf) (s/scale-map [:linear] {:domain (-> conf :extent :y second)})) 43 | ;; render graph 44 | {:keys [canvas fixed? anchor]} (common/render-graph t d conf 45 | {:orientation orientation :w ssize :h size :x sx :y sy}) 46 | ;; axis has already correct anchor 47 | anchor (if fixed? anchor 48 | (case orientation 49 | :top (v/sub anchor [0 size]) 50 | :left (v/sub anchor [size 0]) 51 | anchor))]] 52 | (place-image c canvas anchor imgx imgy)) 53 | (c2d/translate c (* tx size) (* ty size))) 54 | (c2d/pop-matrix c)) 55 | c)) 56 | 57 | ;; inner part 58 | (defn- render-lattice-inner 59 | [c {:keys [rows cols series extents scales left right top bottom] :as srs} 60 | {:keys [padding-in padding-out ^int width ^int height] 61 | :or {padding-in 0.05 padding-out 0.0}}] 62 | (let [[^long l ^long r ^long t ^long b] (map (comp get-max-size srs) [:left :right :top :bottom]) 63 | ww (- width l r) 64 | hh (- height t b) 65 | bands-conf {:padding-in padding-in :padding-out padding-out} 66 | bands-x (common/bands->positions-size (s/bands bands-conf cols) ww) 67 | bands-y-raw (s/bands bands-conf (reverse (range rows))) 68 | bands-y (common/bands->positions-size bands-y-raw hh) 69 | scale-x (:x scales) 70 | scale-y (:y scales)] 71 | 72 | ;; top left corner 73 | (c2d/translate c l t) 74 | 75 | ;; draw lattice 76 | (doseq [[^int x ^int y :as id] (keys series) 77 | :let [[start-x w] (bands-x x) 78 | [start-y h] (bands-y y)]] 79 | 80 | ;; shades 81 | (when (odd? (+ x y)) 82 | (c2d/set-color c :black 20) 83 | (c2d/rect c start-x start-y w h)) 84 | 85 | (doseq [[t d conf] (series id) 86 | :let [sx (scale-x x) 87 | sy (scale-y y) 88 | ex (-> extents :x (get x) second) 89 | ey (-> extents :y (get y) second) 90 | {:keys [canvas anchor]} (common/render-graph t d conf {:w w :h h :x sx :y sy :extent {:x ex :y ey}})]] 91 | 92 | (place-image c canvas (v/add anchor [0 1]) start-x start-y) 93 | 94 | (when-let [label (:label conf)] 95 | (let [lc (common/render-label label w)] 96 | (c2d/image c lc start-x start-y))))) 97 | 98 | ;; draw sides/axes 99 | (-> c 100 | (place-sides left scale-y [-1 0] :left :y bands-y) 101 | (place-sides top scale-x [0 -1] :top :x bands-x) 102 | (c2d/push-matrix) 103 | (c2d/translate ww 0) 104 | (place-sides right scale-y [1 0] :right :y bands-y) 105 | (c2d/pop-matrix) 106 | (c2d/push-matrix) 107 | (c2d/translate 0 hh) 108 | (place-sides bottom scale-x [0 1] :bottom :x bands-x) 109 | (c2d/pop-matrix)) 110 | 111 | [l r t b ww hh])) 112 | 113 | (defn- place-label 114 | [c label px py conf o w h] 115 | (when label 116 | (let [{:keys [canvas anchor]} (common/render-graph :label label (:conf label) 117 | (assoc conf :orientation o :w w :h h))] 118 | (place-image c canvas anchor px py)))) 119 | 120 | ;; outer part (labels, legends, gradients) 121 | (defn render-lattice 122 | ([srs] (render-lattice srs {})) 123 | ([{:keys [labels legend] :or {labels {}} :as srs} 124 | {:keys [^int width ^int height background ^int border] 125 | :or {width 800 height 800 background 0xe8e8f0 border 10} 126 | :as conf}] 127 | 128 | (let [{:keys [left right top bottom]} labels 129 | [^int l ^int r ^int t ^int b] (map (comp #(or % 0) :block-size) [left right top bottom]) 130 | 131 | legend (when legend (ax/legends legend)) 132 | ^int legend-width (or (:block-size legend) 0) 133 | 134 | tl (+ border l) 135 | tt (+ border t) 136 | ww (- width tl r border legend-width) 137 | hh (- height tt b border)] 138 | (c2d/with-canvas [c (c2d/canvas width height)] 139 | 140 | (if (satisfies? p/ImageProto background) 141 | (c2d/image c background) 142 | (c2d/set-background c background)) 143 | 144 | (c2d/push-matrix c) 145 | (c2d/translate c tl tt) 146 | 147 | ;; labels 148 | ;; take inner chart position and sides 149 | (let [[^int il ^int _ir ^int it ^int _ib ^int iw ^int ih] (render-lattice-inner c srs (assoc conf :width ww :height hh))] 150 | 151 | (c2d/pop-matrix c) 152 | (when legend (place-image c (:canvas legend) (:anchor legend) (+ tl ww) (+ it tt))) 153 | (place-label c left border (+ it tt) conf :left ih l) 154 | (place-label c top (+ il tl) border conf :top iw t) 155 | (place-label c bottom (+ il tl) (+ tt hh) conf :bottom iw b) 156 | (place-label c right (+ tl ww legend-width) (+ it tt) conf :right ih r)) 157 | 158 | c)))) 159 | 160 | (m/unuse-primitive-operators) 161 | -------------------------------------------------------------------------------- /src/marchingsquares/Algorithm.java: -------------------------------------------------------------------------------- 1 | package marchingsquares; 2 | 3 | import java.awt.geom.GeneralPath; 4 | import java.util.ArrayList; 5 | import java.util.Collection; 6 | import java.util.List; 7 | import java.util.concurrent.Callable; 8 | import java.util.concurrent.ExecutionException; 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Executors; 11 | import java.util.concurrent.Future; 12 | 13 | /** 14 | *

Implementation of the Marching Squares algorithm described in: 15 | * {@code https://en.wikipedia.org/wiki/Marching_squares}

16 | */ 17 | public class Algorithm 18 | { 19 | private static final ExecutorService ES = Executors.newCachedThreadPool(); 20 | double[] isovalues; 21 | public double min,max; 22 | final double[][] data; 23 | 24 | public Algorithm(final double[][] data) throws IllegalArgumentException { 25 | super(); 26 | double min = data[0][0]; 27 | double max = min; 28 | int rowCount = data.length; 29 | int colCount = data[0].length; 30 | double here; 31 | for (int i = 0; i < rowCount; i++) { 32 | for (int j = 0; j < colCount; j++) { 33 | here = data[i][j]; 34 | min = Math.min(min, here); 35 | max = Math.max(max, here); 36 | } 37 | } 38 | 39 | if (min == max) { 40 | throw new IllegalArgumentException("All values are equal. Cannot build contours for a constant field"); 41 | } 42 | 43 | this.min = min; 44 | this.max = max; 45 | this.data = pad(data, min - 1.0); 46 | 47 | } 48 | 49 | private static Grid contour(double[][] data, double isovalue) { 50 | final int rowCount = data.length; 51 | final int colCount = data[0].length; 52 | 53 | // Every 2x2 block of pixels in the binary image forms a contouring cell, 54 | // so the whole image is represented by a grid of such cells. Note that 55 | // this contouring grid is one cell smaller in each direction than the 56 | // original 2D field. 57 | Cell[][] cells = new Cell[rowCount - 1][colCount - 1]; 58 | for (int r = 0; r < rowCount - 1; r++) { 59 | for (int c = 0; c < colCount - 1; c++) { 60 | // Compose the 4 bits at the corners of the cell to build a binary 61 | // index: walk around the cell in a clockwise direction appending 62 | // the bit to the index, using bitwise OR and left-shift, from most 63 | // significant bit at the top left, to least significant bit at the 64 | // bottom left. The resulting 4-bit index can have 16 possible 65 | // values in the range 0-15. 66 | int ndx = 0; 67 | final double tl = data[r + 1][c ]; 68 | final double tr = data[r + 1][c + 1]; 69 | final double br = data[r ][c + 1]; 70 | final double bl = data[r ][c ]; 71 | ndx |= (tl > isovalue ? 0 : 8); 72 | ndx |= (tr > isovalue ? 0 : 4); 73 | ndx |= (br > isovalue ? 0 : 2); 74 | ndx |= (bl > isovalue ? 0 : 1); 75 | boolean flipped = false; 76 | if (ndx == 5 || ndx == 10) { 77 | // resolve the ambiguity by using the average data value for the 78 | // center of the cell to choose between different connections of 79 | // the interpolated points. 80 | double center = (tl + tr + br + bl) / 4.0; 81 | if (ndx == 5 && center < isovalue) { 82 | flipped = true; 83 | } else if (ndx == 10 && center < isovalue) { 84 | flipped = true; 85 | } 86 | } 87 | // NOTE (rsn) - we only populate the grid w/ non-trivial cells; 88 | // i.e. those w/ an index different than 0 and 15. 89 | if (ndx != 0 && ndx != 15) { 90 | // Apply linear interpolation between the original field data 91 | // values to find the exact position of the contour line along 92 | // the edges of the cell. 93 | float left = 0.5F; 94 | float top = 0.5F; 95 | float right = 0.5F; 96 | float bottom = 0.5F; 97 | switch (ndx) { 98 | case 1: 99 | left = (float)((isovalue - bl) / (tl - bl)); 100 | bottom = (float)((isovalue - bl) / (br - bl)); 101 | break; 102 | case 2: 103 | bottom = (float)((isovalue - bl) / (br - bl)); 104 | right = (float)((isovalue - br) / (tr - br)); 105 | break; 106 | case 3: 107 | left = (float)((isovalue - bl) / (tl - bl)); 108 | right = (float)((isovalue - br) / (tr - br)); 109 | break; 110 | case 4: 111 | top = (float)((isovalue - tl) / (tr - tl)); 112 | right = (float)((isovalue - br) / (tr - br)); 113 | break; 114 | case 5: 115 | left = (float)((isovalue - bl) / (tl - bl)); 116 | bottom = (float)((isovalue - bl) / (br - bl)); 117 | top = (float)((isovalue - tl) / (tr - tl)); 118 | right = (float)((isovalue - br) / (tr - br)); 119 | break; 120 | case 6: 121 | bottom = (float)((isovalue - bl) / (br - bl)); 122 | top = (float)((isovalue - tl) / (tr - tl)); 123 | break; 124 | case 7: 125 | left = (float)((isovalue - bl) / (tl - bl)); 126 | top = (float)((isovalue - tl) / (tr - tl)); 127 | break; 128 | case 8: 129 | left = (float)((isovalue - bl) / (tl - bl)); 130 | top = (float)((isovalue - tl) / (tr - tl)); 131 | break; 132 | case 9: 133 | bottom = (float)((isovalue - bl) / (br - bl)); 134 | top = (float)((isovalue - tl) / (tr - tl)); 135 | break; 136 | case 10: 137 | left = (float)((isovalue - bl) / (tl - bl)); 138 | bottom = (float)((isovalue - bl) / (br - bl)); 139 | top = (float)((isovalue - tl) / (tr - tl)); 140 | right = (float)((isovalue - br) / (tr - br)); 141 | break; 142 | case 11: 143 | top = (float)((isovalue - tl) / (tr - tl)); 144 | right = (float)((isovalue - br) / (tr - br)); 145 | break; 146 | case 12: 147 | left = (float)((isovalue - bl) / (tl - bl)); 148 | right = (float)((isovalue - br) / (tr - br)); 149 | break; 150 | case 13: 151 | bottom = (float)((isovalue - bl) / (br - bl)); 152 | right = (float)((isovalue - br) / (tr - br)); 153 | break; 154 | case 14: 155 | left = (float)((isovalue - bl) / (tl - bl)); 156 | bottom = (float)((isovalue - bl) / (br - bl)); 157 | break; 158 | default: // shouldn't happen 159 | final String m = "Unexpected cell index " + ndx; 160 | throw new IllegalStateException(m); 161 | } 162 | 163 | cells[r][c] = new Cell(ndx, flipped, left, top, right, bottom); 164 | } 165 | } 166 | } 167 | final Grid result = new Grid(cells, isovalue); 168 | return result; 169 | } 170 | 171 | /** 172 | *

Pad data with a given 'guard' value.

173 | * 174 | * @param data matrix to pad. 175 | * @param guard the value to use for padding. It's expected to be less than 176 | * the minimum of all data cell values. 177 | * @return the resulting padded matrix which will be larger by 2 in both 178 | * directions. 179 | */ 180 | private static double[][] pad(double[][] data, double guard) { 181 | final int rowCount = data.length; 182 | final int colCount = data[0].length; 183 | double[][] result = new double[rowCount + 2][colCount + 2]; 184 | 185 | // top and bottom rows 186 | for (int j = 0; j < colCount + 2; j++) { 187 | result[0][j] = guard; 188 | result[rowCount + 1][j] = guard; 189 | } 190 | 191 | // left- and right-most columns excl. top and bottom rows 192 | for (int i = 1; i < rowCount + 1; i++) { 193 | result[i][0] = guard; 194 | result[i][colCount + 1] = guard; 195 | } 196 | 197 | // the middle 198 | for (int i = 0; i < rowCount; i++) { 199 | System.arraycopy(data[i], 0, result[i + 1], 1, colCount); 200 | } 201 | 202 | return result; 203 | } 204 | 205 | public GeneralPath[] buildContours(final double[] levels) 206 | throws InterruptedException, ExecutionException { 207 | isovalues = levels; 208 | 209 | return doConcurrent(); 210 | } 211 | 212 | private GeneralPath[] doConcurrent() 213 | throws InterruptedException, ExecutionException { 214 | final Collection> workers = new ArrayList<>(); 215 | for (int i = 0; i < isovalues.length; i++) { 216 | workers.add(new Task(i, isovalues[i])); 217 | } 218 | 219 | final List> jobs = ES.invokeAll(workers); 220 | final GeneralPath[] result = new GeneralPath[isovalues.length]; 221 | for (final Future future : jobs) { 222 | final Result r = future.get(); 223 | result[r.ndx] = r.path; 224 | } 225 | return result; 226 | } 227 | 228 | private static final class Result 229 | { 230 | final int ndx; 231 | final GeneralPath path; 232 | private transient String str; 233 | 234 | 235 | Result(final int ndx, final GeneralPath path) { 236 | super(); 237 | this.ndx = ndx; 238 | this.path = path; 239 | } 240 | 241 | @Override 242 | public String toString() { 243 | if (str == null) { 244 | str = new StringBuilder("Result{ndx=").append(ndx) 245 | .append(", bbox=").append(path.getBounds()) 246 | .append('}') 247 | .toString(); 248 | } 249 | return str; 250 | } 251 | } 252 | 253 | private final class Task implements Callable 254 | { 255 | private final int ndx; 256 | private final double level; 257 | 258 | 259 | Task(final int ndx, final double level) { 260 | super(); 261 | this.ndx = ndx; 262 | this.level = level; 263 | } 264 | 265 | @Override 266 | public Result call() throws Exception { 267 | GeneralPath path = null; 268 | try { 269 | path = new PathGenerator().generate(contour(data, level)); 270 | } catch (Exception x) { 271 | final String m = "Failed making contour at index #" + ndx 272 | + " for level " + level + ": " + x.getLocalizedMessage(); 273 | System.err.println("Task.call: " + m + ". Rethrow"); 274 | throw x; 275 | } 276 | return new Result(ndx, path); 277 | } 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /src/marchingsquares/Cell.java: -------------------------------------------------------------------------------- 1 | package marchingsquares; 2 | 3 | /** 4 | *

A non-immutable class describing a Marching Squares Contour Cell.

5 | */ 6 | class Cell 7 | { 8 | static enum Side { LEFT, RIGHT, TOP, BOTTOM, NONE } 9 | private byte cellNdx; 10 | private final boolean flipped; 11 | private final float left, top, right, bottom; 12 | 13 | 14 | Cell(int ndx, boolean flipped, float left, float top, float right, float bottom) { 15 | super(); 16 | this.cellNdx = (byte) ndx; 17 | if (flipped && ndx != 5 && ndx != 10) { 18 | System.out.println("Cell: Only saddle cells can be flipped. Will set the " 19 | + "'flipped' flag to FALSE for this (" + ndx + ") cell's index"); 20 | this.flipped = false; 21 | } else { 22 | this.flipped = flipped; 23 | } 24 | this.left = left; 25 | this.top = top; 26 | this.right = right; 27 | this.bottom = bottom; 28 | } 29 | 30 | /** 31 | *

Clear this cell's index.

32 | * 33 | *

When building up shapes, it is possible to have disjoint regions and 34 | * holes in them. An easy way to build up a new shape from the cell's index 35 | * is to build sub-paths for one isoline at a time. As the shape is built 36 | * up, it is necessary to erase the (single) line afterward so that subsequent 37 | * searches for isolines will not loop indefinitely. 38 | */ 39 | void clear() { 40 | switch (cellNdx) { 41 | case 0: 42 | case 5: 43 | case 10: 44 | case 15: 45 | break; 46 | default: 47 | cellNdx = 15; 48 | } 49 | } 50 | 51 | /** @return this cell's algorithm index. */ 52 | byte getCellNdx() { 53 | return cellNdx; 54 | } 55 | 56 | /** 57 | * @param edge which side crossing is wanted. 58 | * @return crossing coordinates (already) normalized to [0.0..1.0]. 59 | */ 60 | float[] getXY(Side edge) { 61 | switch (edge) { 62 | case BOTTOM: return new float[] { bottom, 0.0F }; 63 | case LEFT: return new float[] { 0.0F, left }; 64 | case RIGHT: return new float[] { 1.0F, right }; 65 | case TOP: return new float[] { top, 1.0F }; 66 | default: 67 | throw new IllegalStateException("getXY: N/A w/o a non-trivial edge"); 68 | } 69 | } 70 | 71 | /** @return true if this Cell is a Saddle case. Returns false otherwise. */ 72 | boolean isSaddle() { 73 | return cellNdx == 5 || cellNdx == 10; 74 | } 75 | 76 | /** @return true if this Cell is trivial; otherwise returns false. */ 77 | boolean isTrivial() { 78 | return cellNdx == 0 || cellNdx == 15; 79 | } 80 | 81 | /** @return whether this cell is flipped or not. */ 82 | boolean isFlipped() { 83 | return flipped; 84 | } 85 | 86 | @Override 87 | public String toString() { 88 | return new StringBuilder("Cell{index=").append(cellNdx) 89 | .append(", flipped? ").append(flipped) 90 | .append(", left=").append(left) 91 | .append(", top=").append(top) 92 | .append(", right=").append(right) 93 | .append(", bottom=").append(bottom) 94 | .append('}') 95 | .toString(); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/marchingsquares/Grid.java: -------------------------------------------------------------------------------- 1 | package marchingsquares; 2 | 3 | /** 4 | *

Given a two-dimensional scalar field (rectangular array of individual 5 | * numerical values) the Marching Squares algorithm applies a threshold 6 | * (a.k.a contour level or isovalue) to make a binary image containing:

7 | * 8 | *
    9 | *
  • 1 where the data value is above the isovalue,
  • 10 | *
  • 0 where the data value is below the isovalue.
  • 11 | *
12 | * 13 | *

Every 2x2 block of pixels in the binary image forms a contouring cell, so 14 | * the whole image is represented by a grid of such cells (shown in green in 15 | * the picture below). Note that this contouring grid is one cell smaller in 16 | * each direction than the original 2D data field.

17 | */ 18 | class Grid 19 | { 20 | final Cell[][] cells; 21 | final int rowCount; 22 | final int colCount; 23 | final double threshold; 24 | private transient String str; 25 | 26 | 27 | Grid(final Cell[][] cells, final double threshold) { 28 | super(); 29 | this.cells = cells; 30 | rowCount = cells.length; 31 | colCount = cells[0].length; 32 | this.threshold = threshold; 33 | } 34 | 35 | Cell getCellAt(final int r, final int c) { 36 | return cells[r][c]; 37 | } 38 | 39 | int getCellNdxAt(final int r, final int c) { 40 | final Cell cell = cells[r][c]; 41 | if (cell == null) return 0; 42 | return cells[r][c].getCellNdx(); 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | if (str == null) { 48 | str = new StringBuilder("Grid{rowCount=").append(rowCount) 49 | .append(", colCount=").append(colCount) 50 | .append(", threshold=").append(threshold) 51 | .append('}') 52 | .toString(); 53 | } 54 | return str; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/marchingsquares/PathGenerator.java: -------------------------------------------------------------------------------- 1 | package marchingsquares; 2 | 3 | import static marchingsquares.Cell.Side.BOTTOM; 4 | import static marchingsquares.Cell.Side.LEFT; 5 | import static marchingsquares.Cell.Side.NONE; 6 | import static marchingsquares.Cell.Side.RIGHT; 7 | import static marchingsquares.Cell.Side.TOP; 8 | 9 | import java.awt.geom.GeneralPath; 10 | 11 | import marchingsquares.Cell.Side; 12 | 13 | /** 14 | *

An object that knows how to translate a Grid of Marching Squares Contour 15 | * Cells into a Java AWT General Path.

16 | */ 17 | public class PathGenerator 18 | { 19 | private static final double EPSILON = 1E-7; 20 | 21 | 22 | PathGenerator() { 23 | super(); 24 | } 25 | 26 | /** 27 | *

Construct a GeneralPath representing the isoline, itself represented 28 | * by a given Grid.

29 | * 30 | *

IMPLEMENTATION NOTE: This method is destructive. It alters 31 | * the Grid instance as it generates the resulting path. If the 'original' 32 | * Grid instance is needed after invoking this method then it's the 33 | * responsibility of the caller to deep clone it before passing it here.

34 | * 35 | * @param grid the matrix of contour cells w/ side crossing coordinates 36 | * already interpolated and normalized; i.e. in the range 0.0..1.0. 37 | * @return the geometries of a contour, including sub-path(s) for disjoint 38 | * areas and holes. 39 | */ 40 | GeneralPath generate(final Grid grid) { 41 | GeneralPath result = new GeneralPath(GeneralPath.WIND_EVEN_ODD); 42 | for (int r = 0; r < grid.rowCount; r++) { 43 | for (int c = 0; c < grid.colCount; c++) { 44 | // find a start node... 45 | final Cell cell = grid.getCellAt(r, c); 46 | if (cell != null && !cell.isTrivial() && !cell.isSaddle()) { 47 | // complete the [sub-]path and close it 48 | update(grid, r, c, result); 49 | } 50 | } 51 | } 52 | return result; 53 | } 54 | 55 | /** 56 | *

Return the first side that should be used in a CCW traversal.

57 | * 58 | * @param cell the Cell to process. 59 | * @param prev previous side, only used for saddle cells. 60 | * @return the 1st side of the line segment of the designated cell. 61 | */ 62 | private Side firstSide(final Cell cell, final Side prev) { 63 | switch (cell.getCellNdx()) { 64 | case 1: 65 | case 3: 66 | case 7: 67 | return LEFT; 68 | case 2: 69 | case 6: 70 | case 14: 71 | return BOTTOM; 72 | case 4: 73 | case 11: 74 | case 12: 75 | case 13: 76 | return RIGHT; 77 | case 8: 78 | case 9: 79 | return TOP; 80 | case 5: 81 | switch (prev) { 82 | case LEFT: return RIGHT; 83 | case RIGHT: return LEFT; 84 | default: 85 | final String m = "Saddle w/ no connected neighbour; Cell = " + cell 86 | + ", previous side = " + prev; 87 | System.err.println("firstSide: " + m + ". Throw ISE"); 88 | throw new IllegalStateException(m); 89 | } 90 | case 10: 91 | switch (prev) { 92 | case BOTTOM: return TOP; 93 | case TOP: return BOTTOM; 94 | default: 95 | final String m = "Saddle w/ no connected neighbour; Cell = " + cell 96 | + ", previous side = " + prev; 97 | System.err.println("firstSide: " + m + ". Throw ISE"); 98 | throw new IllegalStateException(m); 99 | } 100 | default: 101 | final String m = "Attempt to use a trivial cell as a start node: " + cell; 102 | System.err.println("firstSide: " + m + ". Throw ISE"); 103 | throw new IllegalStateException(m); 104 | } 105 | } 106 | 107 | /** 108 | *

Find the side on which lies the next cell to use in a CCW traversal.

109 | * 110 | * @param cell the Cell to process. 111 | * @param prev previous side, only used for saddle cells. 112 | * @return side where the next cell is to be picked. 113 | */ 114 | private Side nextSide(final Cell cell, final Side prev) { 115 | return secondSide(cell, prev); 116 | } 117 | 118 | /** 119 | *

Return the second side that should be used in a CCW traversal.

120 | * 121 | * @param cell the Cell to process. 122 | * @param prev previous side, only used for saddle cells. 123 | * @return the 2nd side of the line segment of the designated cell. 124 | */ 125 | private Side secondSide(final Cell cell, final Side prev) { 126 | switch (cell.getCellNdx()) { 127 | case 8: 128 | case 12: 129 | case 14: 130 | return LEFT; 131 | case 1: 132 | case 9: 133 | case 13: 134 | return BOTTOM; 135 | case 2: 136 | case 3: 137 | case 11: 138 | return RIGHT; 139 | case 4: 140 | case 6: 141 | case 7: 142 | return TOP; 143 | case 5: 144 | switch (prev) { 145 | case LEFT: return cell.isFlipped() ? BOTTOM : TOP; 146 | case RIGHT: return cell.isFlipped() ? TOP : BOTTOM; 147 | default: 148 | final String m = "Saddle w/ no connected neighbour; Cell = " + cell 149 | + ", previous side = " + prev; 150 | System.err.println("secondSide: " + m + ". Throw ISE"); 151 | throw new IllegalStateException(m); 152 | } 153 | case 10: 154 | switch (prev) { 155 | case BOTTOM: return cell.isFlipped() ? RIGHT : LEFT; 156 | case TOP: return cell.isFlipped() ? LEFT : RIGHT; 157 | default: 158 | final String m = "Saddle w/ no connected neighbour; Cell = " + cell 159 | + ", previous side = " + prev; 160 | System.err.println("secondSide: " + m + ". Throw ISE"); 161 | throw new IllegalStateException(m); 162 | } 163 | default: 164 | final String m = "Attempt to use a trivial Cell as a node: " + cell; 165 | System.err.println("secondSide: " + m + ". Throw ISE"); 166 | throw new IllegalStateException(m); 167 | } 168 | } 169 | 170 | /** 171 | *

A given contour can be made up of multiple disconnected regions, each 172 | * potentially having multiple holes. Both regions and holes are captured as 173 | * individual sub-paths.

174 | * 175 | *

The process is iterative. It starts w/ an empty GeneralPath instance 176 | * and continues until all Cells are processed. With every invocation the 177 | * GeneralPath object is updated to reflect the new sub-path(s).

178 | * 179 | *

Once a non-saddle cell is used it is cleared so as to ensure it will 180 | * not be re-used when finding sub-paths w/in the original path.

181 | * 182 | * @param grid on input the matrix of cells representing a given contour. 183 | * Note that the process will alter the Cells, so on output the original 184 | * Grid instance _will_ be modified. In other words this method is NOT 185 | * idempotent when using the same object references and values. 186 | * @param r row index of the start Cell. 187 | * @param c column index of the start Cell. 188 | * @param path a non-null GeneralPath instance to update. 189 | */ 190 | private void update(Grid grid, int r, int c, GeneralPath path) { 191 | Side prevSide = NONE; 192 | 193 | Cell start = grid.getCellAt(r, c); 194 | float[] pt = start.getXY(firstSide(start, prevSide)); 195 | float x = c + pt[0]; // may throw NPE 196 | float y = r + pt[1]; // likewise 197 | path.moveTo(x, y); // prepare for a new sub-path 198 | 199 | pt = start.getXY(secondSide(start, prevSide)); 200 | float xPrev = c + pt[0]; 201 | float yPrev = r + pt[1]; 202 | 203 | prevSide = nextSide(start, prevSide); 204 | switch (prevSide) { 205 | case BOTTOM: r--; break; 206 | case LEFT: c--; break; 207 | case RIGHT: c++; break; 208 | case TOP: r++; // fall through 209 | default: // keeps compiler happy + handle NONE case which should never happen 210 | break; 211 | } 212 | start.clear(); 213 | 214 | Cell currentCell = grid.getCellAt(r, c); 215 | while (start != currentCell) { // we want object reference equality 216 | pt = currentCell.getXY(secondSide(currentCell, prevSide)); 217 | x = c + pt[0]; 218 | y = r + pt[1]; 219 | if (Math.abs(x - xPrev) > EPSILON && Math.abs(y - yPrev) > EPSILON) { 220 | path.lineTo(x, y); 221 | } 222 | xPrev = x; 223 | yPrev = y; 224 | prevSide = nextSide(currentCell, prevSide); 225 | switch (prevSide) { 226 | case BOTTOM: r--; break; 227 | case LEFT: c--; break; 228 | case RIGHT: c++; break; 229 | case TOP: r++; break; 230 | default: 231 | System.out.println("update: Potential loop! Current cell = " 232 | + currentCell + ", previous side = " + prevSide); 233 | break; 234 | } 235 | currentCell.clear(); 236 | currentCell = grid.getCellAt(r, c); 237 | } 238 | 239 | path.closePath(); 240 | } 241 | } 242 | --------------------------------------------------------------------------------