diff --git a/PlotlyJS/.devcontainer/devcontainer.json b/PlotlyJS/.devcontainer/devcontainer.json new file mode 100644 index 0000000..bb8eaaf --- /dev/null +++ b/PlotlyJS/.devcontainer/devcontainer.json @@ -0,0 +1,10 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.187.0/containers/julia +// See https://github.com/julia-vscode/julia-devcontainer/blob/master/Dockerfile for image contents +{ + "name": "Julia (Community)", + "image": "ghcr.io/julia-vscode/julia-devcontainer", + "extensions": ["julialang.language-julia"], + "postCreateCommand": "/julia-devcontainer-scripts/postcreate.jl", + "remoteUser": "vscode" +} diff --git a/PlotlyJS/.gitattributes b/PlotlyJS/.gitattributes new file mode 100644 index 0000000..a5530d6 --- /dev/null +++ b/PlotlyJS/.gitattributes @@ -0,0 +1 @@ +*.bundle.js binary diff --git a/PlotlyJS/.gitignore b/PlotlyJS/.gitignore new file mode 100644 index 0000000..0cdd201 --- /dev/null +++ b/PlotlyJS/.gitignore @@ -0,0 +1,18 @@ +*.jl.cov +*.jl.*.cov +*.jl.mem +.vscode/ +tags/ +tags +site/ +.ipynb_checkpoints/ +assets/plotly-latest.min.js +deps/plotly-latest.min.js +deps/plotschema.json +deps/schema.html +deps/*.csv +assets/node_modules/ +assets/package-lock.json +deps/build.log +Manifest.toml +.DS_Store diff --git a/PlotlyJS/.travis.yml b/PlotlyJS/.travis.yml new file mode 100644 index 0000000..f2eb56a --- /dev/null +++ b/PlotlyJS/.travis.yml @@ -0,0 +1,24 @@ +# Documentation: http://docs.travis-ci.com/user/languages/julia/ +language: julia +sudo: required +os: + - linux +julia: + - 1.3 + - 1.4 + - 1.5 + - nightly +matrix: + allow_failures: + - julia: nightly +addons: + apt: + packages: + - xvfb + - xauth + - libgtk-3-0 +notifications: + email: false +# uncomment the following lines to override the default test script +script: + - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi diff --git a/PlotlyJS/Artifacts.toml b/PlotlyJS/Artifacts.toml new file mode 100644 index 0000000..bbf5a64 --- /dev/null +++ b/PlotlyJS/Artifacts.toml @@ -0,0 +1,6 @@ +[plotly-artifacts] +git-tree-sha1 = "77a3f27e7a726685591b11ef3174d43a9a974c9a" + + [[plotly-artifacts.download]] + sha256 = "3b753911705e17ec01d565fa69b5cf08e01b772efed8f4f6e506a0ebea2c6354" + url = "https://github.com/JuliaPlots/PlotlyJS.jl/releases/download/plotly-artifacts-2.3.0/plotly-artifacts-2.3.0.tar.gz" diff --git a/PlotlyJS/CHANGELOG.md b/PlotlyJS/CHANGELOG.md new file mode 100644 index 0000000..5eff0d9 --- /dev/null +++ b/PlotlyJS/CHANGELOG.md @@ -0,0 +1,664 @@ +# Changelog + +## [Unreleased](https://github.com/JuliaPlots/PlotlyJS.jl/tree/HEAD) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.13.1...HEAD) + +**Closed issues:** + +- Update jupyterlab instructions in readme [\#341](https://github.com/JuliaPlots/PlotlyJS.jl/issues/341) +- Link to documentations leads to 404 [\#336](https://github.com/JuliaPlots/PlotlyJS.jl/issues/336) +- Move to JuliaPlots [\#335](https://github.com/JuliaPlots/PlotlyJS.jl/issues/335) +- How to customize download plot options? [\#326](https://github.com/JuliaPlots/PlotlyJS.jl/issues/326) +- Problem for mesh3d intensity [\#324](https://github.com/JuliaPlots/PlotlyJS.jl/issues/324) +- Multiple Spheres in same figure [\#323](https://github.com/JuliaPlots/PlotlyJS.jl/issues/323) +- react! does not update plot [\#317](https://github.com/JuliaPlots/PlotlyJS.jl/issues/317) +- failed process: Process\(`curl -s -S -g -L -f -o /tmp/jl\_G4ODCZ/packages/PlotlyJS/AhkM5/deps/plotschema.json 'https://api.plot.ly/v2/plot-schema?sha1'`, ProcessExited\(22\)\) \[22\] [\#316](https://github.com/JuliaPlots/PlotlyJS.jl/issues/316) +- Neither showEditInChartStudio nor showSendToCloud configurations have any effect [\#313](https://github.com/JuliaPlots/PlotlyJS.jl/issues/313) +- Release patched version [\#306](https://github.com/JuliaPlots/PlotlyJS.jl/issues/306) +- react! eventually kills connection to Plotly [\#264](https://github.com/JuliaPlots/PlotlyJS.jl/issues/264) +- hover attribute does not show x and y coordinates [\#195](https://github.com/JuliaPlots/PlotlyJS.jl/issues/195) + +**Merged pull requests:** + +- Update for Julia 1: Use dot broadcast [\#337](https://github.com/JuliaPlots/PlotlyJS.jl/pull/337) ([diegozea](https://github.com/diegozea)) +- Modify plot window dimensions on creation to fit plot contents [\#315](https://github.com/JuliaPlots/PlotlyJS.jl/pull/315) ([dsfenn](https://github.com/dsfenn)) +- Update line\_scatter.jl [\#310](https://github.com/JuliaPlots/PlotlyJS.jl/pull/310) ([bdeket](https://github.com/bdeket)) +- Install TagBot as a GitHub Action [\#309](https://github.com/JuliaPlots/PlotlyJS.jl/pull/309) ([JuliaTagBot](https://github.com/JuliaTagBot)) +- CompatHelper: add new compat entry for "Requires" at version "1.0" [\#308](https://github.com/JuliaPlots/PlotlyJS.jl/pull/308) ([github-actions[bot]](https://github.com/apps/github-actions)) +- CompatHelper: add new compat entry for "JSExpr" at version "1.0" [\#307](https://github.com/JuliaPlots/PlotlyJS.jl/pull/307) ([github-actions[bot]](https://github.com/apps/github-actions)) + +## [v0.13.1](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.13.1) (2020-01-16) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.13.0...v0.13.1) + +**Closed issues:** + +- Usage of API functions, how does they work in Julia 1.2.0? [\#305](https://github.com/JuliaPlots/PlotlyJS.jl/issues/305) +- Create new labels [\#303](https://github.com/JuliaPlots/PlotlyJS.jl/issues/303) +- "options" keyword does not affect figure [\#300](https://github.com/JuliaPlots/PlotlyJS.jl/issues/300) +- question: how to make this code more compact? [\#298](https://github.com/JuliaPlots/PlotlyJS.jl/issues/298) +- shapes in subplots [\#297](https://github.com/JuliaPlots/PlotlyJS.jl/issues/297) +- Precompilation conflicts [\#294](https://github.com/JuliaPlots/PlotlyJS.jl/issues/294) +- color scale question [\#292](https://github.com/JuliaPlots/PlotlyJS.jl/issues/292) +- Plots don't appear in Juno's plot-pane [\#269](https://github.com/JuliaPlots/PlotlyJS.jl/issues/269) + +**Merged pull requests:** + +- Add pull request labeler [\#301](https://github.com/JuliaPlots/PlotlyJS.jl/pull/301) ([abhishalya](https://github.com/abhishalya)) +- fix \#294 [\#299](https://github.com/JuliaPlots/PlotlyJS.jl/pull/299) ([MoonCoral](https://github.com/MoonCoral)) + +## [v0.13.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.13.0) (2019-10-03) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.12.5...v0.13.0) + +**Closed issues:** + +- savefig fails for html format [\#293](https://github.com/JuliaPlots/PlotlyJS.jl/issues/293) +- Plots on a remote jupyter notebook [\#291](https://github.com/JuliaPlots/PlotlyJS.jl/issues/291) +- annotation [\#290](https://github.com/JuliaPlots/PlotlyJS.jl/issues/290) +- axis attributes do not work for scatter3d [\#287](https://github.com/JuliaPlots/PlotlyJS.jl/issues/287) +- No Output in Notebook \(Julia v1.0.2\) [\#255](https://github.com/JuliaPlots/PlotlyJS.jl/issues/255) + +**Merged pull requests:** + +- show plots in juno plotpane \(fix \#269\) [\#289](https://github.com/JuliaPlots/PlotlyJS.jl/pull/289) ([daschw](https://github.com/daschw)) +- Don't assume a global WebIO instance in JS code \(fix JupyterLab\). [\#288](https://github.com/JuliaPlots/PlotlyJS.jl/pull/288) ([travigd](https://github.com/travigd)) + +## [v0.12.5](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.12.5) (2019-06-28) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.12.4...v0.12.5) + +**Closed issues:** + +- File save error(.eps) [\#284](https://github.com/JuliaPlots/PlotlyJS.jl/issues/284) +- Plots don't display in Jupyter with WebIO v0.8.1 [\#278](https://github.com/JuliaPlots/PlotlyJS.jl/issues/278) + +**Merged pull requests:** + +- Update to latest WebIO. [\#285](https://github.com/JuliaPlots/PlotlyJS.jl/pull/285) ([travigd](https://github.com/travigd)) + +## [v0.12.4](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.12.4) (2019-05-16) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.12.3...v0.12.4) + +**Closed issues:** + +- How to combine heatmap and scatter? [\#280](https://github.com/JuliaPlots/PlotlyJS.jl/issues/280) +- Subplot layout editing issues [\#277](https://github.com/JuliaPlots/PlotlyJS.jl/issues/277) +- Failed to Precompile Mux, Blink, PlotlyJS [\#275](https://github.com/JuliaPlots/PlotlyJS.jl/issues/275) +- Julia : ERROR: KeyError: key "set\_facecolor" not found [\#270](https://github.com/JuliaPlots/PlotlyJS.jl/issues/270) +- Missing support [\#265](https://github.com/JuliaPlots/PlotlyJS.jl/issues/265) +- Cannot savefig to html on Julia 1.0.3 [\#263](https://github.com/JuliaPlots/PlotlyJS.jl/issues/263) +- Selecting points no longer works [\#262](https://github.com/JuliaPlots/PlotlyJS.jl/issues/262) + +**Merged pull requests:** + +- Revert "Add fix for WebIO 0.8.0+." [\#279](https://github.com/JuliaPlots/PlotlyJS.jl/pull/279) ([sglyon](https://github.com/sglyon)) +- Broadcasting change in Julia 1.1 [\#274](https://github.com/JuliaPlots/PlotlyJS.jl/pull/274) ([jlperla](https://github.com/jlperla)) +- Add fix for WebIO 0.8.0+. [\#267](https://github.com/JuliaPlots/PlotlyJS.jl/pull/267) ([travigd](https://github.com/travigd)) +- Do not recursively call JSON.lower [\#266](https://github.com/JuliaPlots/PlotlyJS.jl/pull/266) ([TotalVerb](https://github.com/TotalVerb)) +- Check for data files before downloading them during build. [\#237](https://github.com/JuliaPlots/PlotlyJS.jl/pull/237) ([jjstickel](https://github.com/jjstickel)) + +## [v0.12.3](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.12.3) (2019-01-23) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.12.2...v0.12.3) + +**Closed issues:** + +- index.js and display.jl out of sync [\#261](https://github.com/JuliaPlots/PlotlyJS.jl/issues/261) +- WebGL / Max Dataset Size/Data Point Quantity? [\#260](https://github.com/JuliaPlots/PlotlyJS.jl/issues/260) +- Error when "using Blink" [\#259](https://github.com/JuliaPlots/PlotlyJS.jl/issues/259) + +## [v0.12.2](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.12.2) (2018-12-29) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.12.1...v0.12.2) + +**Closed issues:** + +- \_use\_remote not defined [\#257](https://github.com/JuliaPlots/PlotlyJS.jl/issues/257) +- Subplots do not scale correctly when using plotlyjs\(\) with Plots.jl [\#256](https://github.com/JuliaPlots/PlotlyJS.jl/issues/256) +- Blank plots [\#254](https://github.com/JuliaPlots/PlotlyJS.jl/issues/254) + +**Merged pull requests:** + +- Insert PlotlyJSDisplay just after REPL instead of pushing. [\#258](https://github.com/JuliaPlots/PlotlyJS.jl/pull/258) ([EricForgy](https://github.com/EricForgy)) + +## [v0.12.1](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.12.1) (2018-12-03) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.12.0...v0.12.1) + +**Closed issues:** + +- Blink/Atom/Electron not connecting properly to PlotlyJS [\#253](https://github.com/JuliaPlots/PlotlyJS.jl/issues/253) +- Transforms [\#252](https://github.com/JuliaPlots/PlotlyJS.jl/issues/252) + +## [v0.12.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.12.0) (2018-11-05) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.11.2...v0.12.0) + +**Closed issues:** + +- Styles not working as expected [\#249](https://github.com/JuliaPlots/PlotlyJS.jl/issues/249) +- Issues with displaying plot in jupyter-lab [\#248](https://github.com/JuliaPlots/PlotlyJS.jl/issues/248) +- Can't add PlotlyJS [\#246](https://github.com/JuliaPlots/PlotlyJS.jl/issues/246) +- Blank plots [\#245](https://github.com/JuliaPlots/PlotlyJS.jl/issues/245) +- seeming regression on Julia 0.7 [\#239](https://github.com/JuliaPlots/PlotlyJS.jl/issues/239) +- Plotly examples do not work [\#236](https://github.com/JuliaPlots/PlotlyJS.jl/issues/236) +- PlotlyJS plots not showing up in Juno/ijulia [\#235](https://github.com/JuliaPlots/PlotlyJS.jl/issues/235) +- Layout: strange bug [\#234](https://github.com/JuliaPlots/PlotlyJS.jl/issues/234) +- Juno compatibility [\#229](https://github.com/JuliaPlots/PlotlyJS.jl/issues/229) + +**Merged pull requests:** + +- Fix the link to the Plots.jl homepage in index.md [\#247](https://github.com/JuliaPlots/PlotlyJS.jl/pull/247) ([Kryohi](https://github.com/Kryohi)) +- Fixed a typo in the docs [\#241](https://github.com/JuliaPlots/PlotlyJS.jl/pull/241) ([ghuba](https://github.com/ghuba)) + +## [v0.11.2](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.11.2) (2018-09-27) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.11.1...v0.11.2) + +**Closed issues:** + +- How to clear a figure without generating an error? [\#233](https://github.com/JuliaPlots/PlotlyJS.jl/issues/233) +- JSString not defined [\#232](https://github.com/JuliaPlots/PlotlyJS.jl/issues/232) +- OSTYPE environmental variable in ORCA/deps/bin [\#228](https://github.com/JuliaPlots/PlotlyJS.jl/issues/228) +- Cones and streamtubes [\#227](https://github.com/JuliaPlots/PlotlyJS.jl/issues/227) +- ColorBrewer palettes not working in PlotlyJS v0.11.1 [\#225](https://github.com/JuliaPlots/PlotlyJS.jl/issues/225) +- Dynamical plotting with extendtraces! in Julia 0.7 [\#223](https://github.com/JuliaPlots/PlotlyJS.jl/issues/223) +- Plots integration still not working [\#222](https://github.com/JuliaPlots/PlotlyJS.jl/issues/222) +- Feature request: Parallel Coordinates Plot [\#218](https://github.com/JuliaPlots/PlotlyJS.jl/issues/218) + +**Merged pull requests:** + +- use webio for Juno integration [\#231](https://github.com/JuliaPlots/PlotlyJS.jl/pull/231) ([pfitzseb](https://github.com/pfitzseb)) +- ENH: enables dynamical plotting when run in terminal or atom [\#224](https://github.com/JuliaPlots/PlotlyJS.jl/pull/224) ([kleskjr](https://github.com/kleskjr)) + +## [v0.11.1](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.11.1) (2018-09-06) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.11.0...v0.11.1) + +**Closed issues:** + +- Can't close plot windows programmatically [\#220](https://github.com/JuliaPlots/PlotlyJS.jl/issues/220) +- used to work; doesn't now [\#219](https://github.com/JuliaPlots/PlotlyJS.jl/issues/219) +- Error while building the package in Julia 0.7 [\#217](https://github.com/JuliaPlots/PlotlyJS.jl/issues/217) +- Missing "Reexport" dependency [\#215](https://github.com/JuliaPlots/PlotlyJS.jl/issues/215) +- Cannot display under Atom/Juno \(Julia v0.7.0\) [\#214](https://github.com/JuliaPlots/PlotlyJS.jl/issues/214) +- Not sure if this warning is yours.... [\#196](https://github.com/JuliaPlots/PlotlyJS.jl/issues/196) + +## [v0.11.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.11.0) (2018-09-05) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.10.3...v0.11.0) + +**Implemented enhancements:** + +- Integrate with the display-backend stack [\#122](https://github.com/JuliaPlots/PlotlyJS.jl/issues/122) + +**Closed issues:** + +- Markdown not defined on master during build [\#212](https://github.com/JuliaPlots/PlotlyJS.jl/issues/212) +- UndefVarError: plotattributes not defined [\#211](https://github.com/JuliaPlots/PlotlyJS.jl/issues/211) +- Error building - Julia 1.0 [\#210](https://github.com/JuliaPlots/PlotlyJS.jl/issues/210) +- Manual redraw! [\#209](https://github.com/JuliaPlots/PlotlyJS.jl/issues/209) +- Fails to build or precompile on Julia 1.0.0 - Markdown not defined [\#207](https://github.com/JuliaPlots/PlotlyJS.jl/issues/207) +- Failure on Linux, 0.7.0 [\#205](https://github.com/JuliaPlots/PlotlyJS.jl/issues/205) +- Error building `PlotlyJS` on 1.0.0 [\#204](https://github.com/JuliaPlots/PlotlyJS.jl/issues/204) +- PlotlyJS can't be built on Julia 0.7 [\#203](https://github.com/JuliaPlots/PlotlyJS.jl/issues/203) +- Build failure of master \(v0.10.2\) on julia 1.0: `Markdown not defined` [\#202](https://github.com/JuliaPlots/PlotlyJS.jl/issues/202) +- Failure to precompile under Julia v0.7.0: Date not defined [\#201](https://github.com/JuliaPlots/PlotlyJS.jl/issues/201) +- Failure to Precompile: JSString not defined [\#198](https://github.com/JuliaPlots/PlotlyJS.jl/issues/198) +- Failing to plot locally, Julia0.6.4 OSX [\#197](https://github.com/JuliaPlots/PlotlyJS.jl/issues/197) +- savefig areaplot [\#192](https://github.com/JuliaPlots/PlotlyJS.jl/issues/192) +- Add show for "application/vnd.plotly.v1+json" mime type [\#191](https://github.com/JuliaPlots/PlotlyJS.jl/issues/191) +- displayModeBar = false [\#185](https://github.com/JuliaPlots/PlotlyJS.jl/issues/185) +- Remove Blink dependency? [\#184](https://github.com/JuliaPlots/PlotlyJS.jl/issues/184) +- savefig stacked in a while loop for saving a subplot from Plots.jl [\#180](https://github.com/JuliaPlots/PlotlyJS.jl/issues/180) +- Build fails on julia-0.6.0 [\#179](https://github.com/JuliaPlots/PlotlyJS.jl/issues/179) +- Ensuring Blink.AtomShell.install\(\) called [\#175](https://github.com/JuliaPlots/PlotlyJS.jl/issues/175) +- Issue generating figures with a for loop [\#165](https://github.com/JuliaPlots/PlotlyJS.jl/issues/165) +- Module Options [\#108](https://github.com/JuliaPlots/PlotlyJS.jl/issues/108) +- Hook into plotly events [\#27](https://github.com/JuliaPlots/PlotlyJS.jl/issues/27) + +**Merged pull requests:** + +- info -\> @info [\#216](https://github.com/JuliaPlots/PlotlyJS.jl/pull/216) ([cstjean](https://github.com/cstjean)) +- Import html\_body from PlotlyBase [\#213](https://github.com/JuliaPlots/PlotlyJS.jl/pull/213) ([cstjean](https://github.com/cstjean)) +- WIP: Sl/0.7 [\#208](https://github.com/JuliaPlots/PlotlyJS.jl/pull/208) ([sglyon](https://github.com/sglyon)) +- Fix deprecations [\#206](https://github.com/JuliaPlots/PlotlyJS.jl/pull/206) ([femtocleaner[bot]](https://github.com/apps/femtocleaner)) +- Fixes for Julia v0.7 [\#200](https://github.com/JuliaPlots/PlotlyJS.jl/pull/200) ([VPetukhov](https://github.com/VPetukhov)) +- webio integration [\#193](https://github.com/JuliaPlots/PlotlyJS.jl/pull/193) ([piever](https://github.com/piever)) + +## [v0.10.3](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.10.3) (2018-06-23) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.10.2...v0.10.3) + +**Closed issues:** + +- Fail to plot scatter3d [\#190](https://github.com/JuliaPlots/PlotlyJS.jl/issues/190) +- changes in scatter3d axis label specification? [\#189](https://github.com/JuliaPlots/PlotlyJS.jl/issues/189) +- Unable to use `scatter` [\#188](https://github.com/JuliaPlots/PlotlyJS.jl/issues/188) +- currently uninstallable on 0.6.2. [\#187](https://github.com/JuliaPlots/PlotlyJS.jl/issues/187) +- Adding logo [\#186](https://github.com/JuliaPlots/PlotlyJS.jl/issues/186) + +## [v0.10.2](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.10.2) (2018-03-05) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.10.1...v0.10.2) + +**Closed issues:** + +- JupyterLab incompatibility [\#182](https://github.com/JuliaPlots/PlotlyJS.jl/issues/182) +- Error requiring IJulia from PlotlyJS [\#181](https://github.com/JuliaPlots/PlotlyJS.jl/issues/181) + +**Merged pull requests:** + +- Fix paths in build.jl [\#183](https://github.com/JuliaPlots/PlotlyJS.jl/pull/183) ([EricForgy](https://github.com/EricForgy)) + +## [v0.10.1](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.10.1) (2018-02-07) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.10.0...v0.10.1) + +**Closed issues:** + +- Installation issue on local computer: plotly.js javascript libary not found - [\#176](https://github.com/JuliaPlots/PlotlyJS.jl/issues/176) +- Allow calling init\_notebook outside of jupyter [\#174](https://github.com/JuliaPlots/PlotlyJS.jl/issues/174) +- ERROR: LoadError: Cannot find Electron. [\#172](https://github.com/JuliaPlots/PlotlyJS.jl/issues/172) +- Require DataFrames failed [\#169](https://github.com/JuliaPlots/PlotlyJS.jl/issues/169) +- Add violin trace [\#167](https://github.com/JuliaPlots/PlotlyJS.jl/issues/167) +- save to pdf [\#137](https://github.com/JuliaPlots/PlotlyJS.jl/issues/137) + +## [v0.10.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.10.0) (2018-02-01) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.9.0...v0.10.0) + +**Closed issues:** + +- Blink Display error [\#170](https://github.com/JuliaPlots/PlotlyJS.jl/issues/170) + +**Merged pull requests:** + +- Sl/plotlybase [\#171](https://github.com/JuliaPlots/PlotlyJS.jl/pull/171) ([sglyon](https://github.com/sglyon)) + +## [v0.9.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.9.0) (2018-01-20) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.8.3...v0.9.0) + +**Fixed bugs:** + +- Race condition with Blink.jl v0.6.0 and onwards [\#162](https://github.com/JuliaPlots/PlotlyJS.jl/issues/162) + +**Closed issues:** + +- Blink/ElectronDisplay [\#164](https://github.com/JuliaPlots/PlotlyJS.jl/issues/164) + +**Merged pull requests:** + +- Violins [\#168](https://github.com/JuliaPlots/PlotlyJS.jl/pull/168) ([sglyon](https://github.com/sglyon)) +- Fixed some typos [\#166](https://github.com/JuliaPlots/PlotlyJS.jl/pull/166) ([ghuba](https://github.com/ghuba)) +- add subplot examples [\#163](https://github.com/JuliaPlots/PlotlyJS.jl/pull/163) ([jbrea](https://github.com/jbrea)) + +## [v0.8.3](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.8.3) (2018-01-11) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.8.2...v0.8.3) + +**Fixed bugs:** + +- `by` not defined [\#158](https://github.com/JuliaPlots/PlotlyJS.jl/issues/158) + +**Closed issues:** + +- Subplots generated with comprehension don't show up in Electron in REPL [\#160](https://github.com/JuliaPlots/PlotlyJS.jl/issues/160) + +## [v0.8.2](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.8.2) (2018-01-06) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.8.1...v0.8.2) + +## [v0.8.1](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.8.1) (2017-12-19) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.8.0...v0.8.1) + +**Fixed bugs:** + +- Do subplots work with surfaces? [\#156](https://github.com/JuliaPlots/PlotlyJS.jl/issues/156) + +**Closed issues:** + +- apply "columnar" attributes to each series [\#154](https://github.com/JuliaPlots/PlotlyJS.jl/issues/154) +- Error tagging new release [\#153](https://github.com/JuliaPlots/PlotlyJS.jl/issues/153) +- DataFrames v0.11 [\#151](https://github.com/JuliaPlots/PlotlyJS.jl/issues/151) +- right side of plot is not using correct color [\#148](https://github.com/JuliaPlots/PlotlyJS.jl/issues/148) +- subplots throw away shape information [\#138](https://github.com/JuliaPlots/PlotlyJS.jl/issues/138) +- LoadError: Javascript error [\#116](https://github.com/JuliaPlots/PlotlyJS.jl/issues/116) +- RE: EOFError: read end of file [\#105](https://github.com/JuliaPlots/PlotlyJS.jl/issues/105) +- Giant memory leak. [\#102](https://github.com/JuliaPlots/PlotlyJS.jl/issues/102) +- histogram crashing when using PlotlyJS over ssh tunnel [\#101](https://github.com/JuliaPlots/PlotlyJS.jl/issues/101) +- Generating ElectronPlot/ saving plots from Jupyter Notebook [\#88](https://github.com/JuliaPlots/PlotlyJS.jl/issues/88) +- Properties with underscores not handled correctly on trace creation [\#76](https://github.com/JuliaPlots/PlotlyJS.jl/issues/76) +- Wishlist [\#61](https://github.com/JuliaPlots/PlotlyJS.jl/issues/61) +- line labels and legends for subplots collect next to the first subplot [\#59](https://github.com/JuliaPlots/PlotlyJS.jl/issues/59) +- Save multiple plots to single html file \(no subplots\) [\#43](https://github.com/JuliaPlots/PlotlyJS.jl/issues/43) +- Add options for savefig [\#4](https://github.com/JuliaPlots/PlotlyJS.jl/issues/4) + +**Merged pull requests:** + +- ENH: subplots with 3d works closes \#156 [\#157](https://github.com/JuliaPlots/PlotlyJS.jl/pull/157) ([sglyon](https://github.com/sglyon)) + +## [v0.8.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.8.0) (2017-12-12) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.7.1...v0.8.0) + +**Closed issues:** + +- Plot won't display in Atom or in Blink window [\#147](https://github.com/JuliaPlots/PlotlyJS.jl/issues/147) +- Advanced heatmap features help [\#146](https://github.com/JuliaPlots/PlotlyJS.jl/issues/146) +- "updatemenus" support [\#144](https://github.com/JuliaPlots/PlotlyJS.jl/issues/144) +- PlotlyJS \(as a Plots.jl backend\) now fails in Juno \(Atom\) on Ubuntu 16.04 [\#142](https://github.com/JuliaPlots/PlotlyJS.jl/issues/142) +- Possible issue - Error during installation [\#141](https://github.com/JuliaPlots/PlotlyJS.jl/issues/141) +- Run femtocleaner [\#140](https://github.com/JuliaPlots/PlotlyJS.jl/issues/140) +- Unable to install PlotlyJS on Julia 0.6 on Mac [\#139](https://github.com/JuliaPlots/PlotlyJS.jl/issues/139) + +**Merged pull requests:** + +- Develop [\#152](https://github.com/JuliaPlots/PlotlyJS.jl/pull/152) ([sglyon](https://github.com/sglyon)) +- Tiny Cycler fixes [\#149](https://github.com/JuliaPlots/PlotlyJS.jl/pull/149) ([alyst](https://github.com/alyst)) +- use Requires.jl [\#145](https://github.com/JuliaPlots/PlotlyJS.jl/pull/145) ([sglyon](https://github.com/sglyon)) + +## [v0.7.1](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.7.1) (2017-10-25) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.7.0...v0.7.1) + +**Merged pull requests:** + +- Sl/cyclers [\#143](https://github.com/JuliaPlots/PlotlyJS.jl/pull/143) ([sglyon](https://github.com/sglyon)) + +## [v0.7.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.7.0) (2017-10-20) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.6.5...v0.7.0) + +## [v0.6.5](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.6.5) (2017-10-20) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.6.4...v0.6.5) + +**Closed issues:** + +- Hover text doesn't handle same-x data points [\#135](https://github.com/JuliaPlots/PlotlyJS.jl/issues/135) +- HTML output points to a local copy of plotly.js [\#133](https://github.com/JuliaPlots/PlotlyJS.jl/issues/133) +- Inconistent numeric format on logarithmic axis labels [\#132](https://github.com/JuliaPlots/PlotlyJS.jl/issues/132) +- Titles cut off of example plots in documentation [\#131](https://github.com/JuliaPlots/PlotlyJS.jl/issues/131) +- Empty plots in Jupyter notebooks [\#130](https://github.com/JuliaPlots/PlotlyJS.jl/issues/130) +- Using julia 0.6: `filter\(flt, itr\) is deprecated` [\#124](https://github.com/JuliaPlots/PlotlyJS.jl/issues/124) +- no show \(Windows 7, Julia 0.5, electron\) [\#81](https://github.com/JuliaPlots/PlotlyJS.jl/issues/81) + +**Merged pull requests:** + +- Fix deprecations [\#134](https://github.com/JuliaPlots/PlotlyJS.jl/pull/134) ([femtocleaner[bot]](https://github.com/apps/femtocleaner)) + +## [v0.6.4](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.6.4) (2017-07-13) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.6.3...v0.6.4) + +**Closed issues:** + +- Subplots not appearing [\#128](https://github.com/JuliaPlots/PlotlyJS.jl/issues/128) +- Transparent surface plots [\#126](https://github.com/JuliaPlots/PlotlyJS.jl/issues/126) +- Error showing value of type PlotlyJS.SyncPlot{PlotlyJS.ElectronDisplay} [\#110](https://github.com/JuliaPlots/PlotlyJS.jl/issues/110) + +**Merged pull requests:** + +- Abstrrrract [\#129](https://github.com/JuliaPlots/PlotlyJS.jl/pull/129) ([JobJob](https://github.com/JobJob)) +- Readall rename and Js loading default [\#127](https://github.com/JuliaPlots/PlotlyJS.jl/pull/127) ([JobJob](https://github.com/JobJob)) + +## [v0.6.3](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.6.3) (2017-06-26) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.6.2...v0.6.3) + +**Closed issues:** + +- Failed to precompile PlotlyJS on windows, Julia 0.5 [\#123](https://github.com/JuliaPlots/PlotlyJS.jl/issues/123) +- xaxis\_title in mesh3d [\#121](https://github.com/JuliaPlots/PlotlyJS.jl/issues/121) +- Changing colorscale in Scatter Plots [\#117](https://github.com/JuliaPlots/PlotlyJS.jl/issues/117) +- Error handling websocket connection [\#115](https://github.com/JuliaPlots/PlotlyJS.jl/issues/115) +- Feature request: DateTime support [\#87](https://github.com/JuliaPlots/PlotlyJS.jl/issues/87) +- savefig hangs if the plot hasn't been displayed for long enough [\#73](https://github.com/JuliaPlots/PlotlyJS.jl/issues/73) +- Using with Hydrogen? [\#42](https://github.com/JuliaPlots/PlotlyJS.jl/issues/42) + +**Merged pull requests:** + +- Update CI URLs to point to new caching infrastructure [\#120](https://github.com/JuliaPlots/PlotlyJS.jl/pull/120) ([staticfloat](https://github.com/staticfloat)) +- Fix duplicate setting of keyword parameter, test more versions, add badges [\#119](https://github.com/JuliaPlots/PlotlyJS.jl/pull/119) ([ScottPJones](https://github.com/ScottPJones)) + +## [v0.6.2](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.6.2) (2017-05-01) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.6.1...v0.6.2) + +## [v0.6.1](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.6.1) (2017-04-28) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.6.0...v0.6.1) + +## [v0.6.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.6.0) (2017-04-14) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.5.2...v0.6.0) + +**Closed issues:** + +- HTML script virus in examples [\#113](https://github.com/JuliaPlots/PlotlyJS.jl/issues/113) +- 2D-Histogram examples are not working [\#111](https://github.com/JuliaPlots/PlotlyJS.jl/issues/111) +- close plot window [\#109](https://github.com/JuliaPlots/PlotlyJS.jl/issues/109) +- Errors arise after clearing workspace [\#107](https://github.com/JuliaPlots/PlotlyJS.jl/issues/107) +- plot heatmap function gives a compile error when working on a variable from a global scope [\#106](https://github.com/JuliaPlots/PlotlyJS.jl/issues/106) +- Plotting a 3D surface with facecolor different from its height values [\#104](https://github.com/JuliaPlots/PlotlyJS.jl/issues/104) +- WARNING: bytestring is deprecated [\#103](https://github.com/JuliaPlots/PlotlyJS.jl/issues/103) +- clims in heatmap not supported? [\#99](https://github.com/JuliaPlots/PlotlyJS.jl/issues/99) +- Plot, plot, \[plots\] and docs [\#74](https://github.com/JuliaPlots/PlotlyJS.jl/issues/74) + +**Merged pull requests:** + +- Sl/dataframes [\#112](https://github.com/JuliaPlots/PlotlyJS.jl/pull/112) ([sglyon](https://github.com/sglyon)) + +## [v0.5.2](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.5.2) (2016-12-07) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.5.1...v0.5.2) + +**Closed issues:** + +- Plot is too big? [\#98](https://github.com/JuliaPlots/PlotlyJS.jl/issues/98) +- Stacked subplots, more than 2 yaxis [\#96](https://github.com/JuliaPlots/PlotlyJS.jl/issues/96) +- Loaded notebooks have no plots [\#89](https://github.com/JuliaPlots/PlotlyJS.jl/issues/89) + +**Merged pull requests:** + +- Complete Contour Examples [\#95](https://github.com/JuliaPlots/PlotlyJS.jl/pull/95) ([caimichael](https://github.com/caimichael)) +- adds TestSetExtensions to clean up test results [\#93](https://github.com/JuliaPlots/PlotlyJS.jl/pull/93) ([ssfrr](https://github.com/ssfrr)) +- Simpler way to fix use with Interact in IJulia on page refresh [\#92](https://github.com/JuliaPlots/PlotlyJS.jl/pull/92) ([JobJob](https://github.com/JobJob)) + +## [v0.5.1](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.5.1) (2016-10-29) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.5.0...v0.5.1) + +**Closed issues:** + +- Add nteract support for JupyterPlot [\#90](https://github.com/JuliaPlots/PlotlyJS.jl/issues/90) +- Aspect ratio for 2D plot [\#85](https://github.com/JuliaPlots/PlotlyJS.jl/issues/85) +- error install :\( [\#83](https://github.com/JuliaPlots/PlotlyJS.jl/issues/83) +- handle 2D data matrices in 1D plots e.g. `scatter` [\#82](https://github.com/JuliaPlots/PlotlyJS.jl/issues/82) +- Grab gadfly dark theme [\#79](https://github.com/JuliaPlots/PlotlyJS.jl/issues/79) +- Float32 arrays don't plot reliably on 0.5.0 [\#78](https://github.com/JuliaPlots/PlotlyJS.jl/issues/78) +- Save and edit plot in cloud [\#75](https://github.com/JuliaPlots/PlotlyJS.jl/issues/75) + +**Merged pull requests:** + +- adds stem plot trace as wrapper around `scatter` [\#86](https://github.com/JuliaPlots/PlotlyJS.jl/pull/86) ([ssfrr](https://github.com/ssfrr)) +- Use dark theme in Juno [\#84](https://github.com/JuliaPlots/PlotlyJS.jl/pull/84) ([MikeInnes](https://github.com/MikeInnes)) +- Examples completed [\#71](https://github.com/JuliaPlots/PlotlyJS.jl/pull/71) ([caimichael](https://github.com/caimichael)) + +## [v0.5.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.5.0) (2016-09-21) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.4.3...v0.5.0) + +## [v0.4.3](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.4.3) (2016-09-21) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.4.2...v0.4.3) + +**Merged pull requests:** + +- Caimichael/examples [\#72](https://github.com/JuliaPlots/PlotlyJS.jl/pull/72) ([sglyon](https://github.com/sglyon)) + +## [v0.4.2](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.4.2) (2016-09-07) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.4.1...v0.4.2) + +**Closed issues:** + +- Error updating package [\#70](https://github.com/JuliaPlots/PlotlyJS.jl/issues/70) + +## [v0.4.1](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.4.1) (2016-09-07) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.4.0...v0.4.1) + +**Merged pull requests:** + +- don't use a generator in \_symbol\_dict [\#69](https://github.com/JuliaPlots/PlotlyJS.jl/pull/69) ([tkelman](https://github.com/tkelman)) + +## [v0.4.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.4.0) (2016-09-07) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.3.3...v0.4.0) + +**Closed issues:** + +- PlotlyJS doesn't show plots on Julia 0.5 RC3. [\#68](https://github.com/JuliaPlots/PlotlyJS.jl/issues/68) + +**Merged pull requests:** + +- RFC: start for more convenient `plot` API [\#66](https://github.com/JuliaPlots/PlotlyJS.jl/pull/66) ([sglyon](https://github.com/sglyon)) + +## [v0.3.3](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.3.3) (2016-08-24) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.3.2...v0.3.3) + +## [v0.3.2](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.3.2) (2016-08-23) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.3.1...v0.3.2) + +**Closed issues:** + +- Does PlotlyJS.jl support unicode now? [\#64](https://github.com/JuliaPlots/PlotlyJS.jl/issues/64) +- Loading PlotlyJS fails on Julia V0.5-rc1 [\#62](https://github.com/JuliaPlots/PlotlyJS.jl/issues/62) +- Cloud [\#55](https://github.com/JuliaPlots/PlotlyJS.jl/issues/55) +- Plots.jl animations [\#53](https://github.com/JuliaPlots/PlotlyJS.jl/issues/53) +- ERROR: connect: connection refused \(ECONNREFUSED\) [\#33](https://github.com/JuliaPlots/PlotlyJS.jl/issues/33) +- Include MathJax.js [\#30](https://github.com/JuliaPlots/PlotlyJS.jl/issues/30) +- Javascript error on package load with IJulia/Firefox [\#28](https://github.com/JuliaPlots/PlotlyJS.jl/issues/28) +- Resize plot when electron window is resized [\#25](https://github.com/JuliaPlots/PlotlyJS.jl/issues/25) + +**Merged pull requests:** + +- Extend `JSON.lower` instead of `JSON.print` [\#65](https://github.com/JuliaPlots/PlotlyJS.jl/pull/65) ([TotalVerb](https://github.com/TotalVerb)) +- Fixes for Julia 0.5 [\#63](https://github.com/JuliaPlots/PlotlyJS.jl/pull/63) ([timholy](https://github.com/timholy)) +- fix dates in json [\#58](https://github.com/JuliaPlots/PlotlyJS.jl/pull/58) ([tbreloff](https://github.com/tbreloff)) +- Update README [\#57](https://github.com/JuliaPlots/PlotlyJS.jl/pull/57) ([matthieugomez](https://github.com/matthieugomez)) +- Solve issue \#55 [\#56](https://github.com/JuliaPlots/PlotlyJS.jl/pull/56) ([matthieugomez](https://github.com/matthieugomez)) + +## [v0.3.1](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.3.1) (2016-06-22) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.3.0...v0.3.1) + +**Closed issues:** + +- Electron backend on Windows throws error [\#51](https://github.com/JuliaPlots/PlotlyJS.jl/issues/51) +- Error when saving as pdf using Electron Display [\#50](https://github.com/JuliaPlots/PlotlyJS.jl/issues/50) +- Reloaded notebook's PlotlyJS doesn't work [\#45](https://github.com/JuliaPlots/PlotlyJS.jl/issues/45) + +**Merged pull requests:** + +- Remove `kind` field for GenericTrace and Shape. [\#54](https://github.com/JuliaPlots/PlotlyJS.jl/pull/54) ([sglyon](https://github.com/sglyon)) + +## [v0.3.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.3.0) (2016-06-17) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.2.0...v0.3.0) + +**Closed issues:** + +- Error when plotting in IJulia notebooks [\#46](https://github.com/JuliaPlots/PlotlyJS.jl/issues/46) +- Error message with savefig [\#44](https://github.com/JuliaPlots/PlotlyJS.jl/issues/44) +- Background not set? [\#36](https://github.com/JuliaPlots/PlotlyJS.jl/issues/36) +- How to save the JSON object [\#35](https://github.com/JuliaPlots/PlotlyJS.jl/issues/35) + +**Merged pull requests:** + +- Sl/savefig [\#49](https://github.com/JuliaPlots/PlotlyJS.jl/pull/49) ([sglyon](https://github.com/sglyon)) +- Update use of JSON.colon to JSON.separator [\#48](https://github.com/JuliaPlots/PlotlyJS.jl/pull/48) ([cdsousa](https://github.com/cdsousa)) +- Compat update for String rename [\#40](https://github.com/JuliaPlots/PlotlyJS.jl/pull/40) ([StefanKarpinski](https://github.com/StefanKarpinski)) +- JSON for vectors of traces. [\#39](https://github.com/JuliaPlots/PlotlyJS.jl/pull/39) ([EricForgy](https://github.com/EricForgy)) +- Let string interpolation stringify to JSON format [\#38](https://github.com/JuliaPlots/PlotlyJS.jl/pull/38) ([EricForgy](https://github.com/EricForgy)) + +## [v0.2.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.2.0) (2016-05-04) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.1.4...v0.2.0) + +**Closed issues:** + +- Why is `text` using only the first element of a `Vector{ASCIIString}`? [\#34](https://github.com/JuliaPlots/PlotlyJS.jl/issues/34) + +## [v0.1.4](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.1.4) (2016-03-31) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.1.3...v0.1.4) + +**Closed issues:** + +- PlotlyJS doesn't work with Interact [\#31](https://github.com/JuliaPlots/PlotlyJS.jl/issues/31) + +## [v0.1.3](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.1.3) (2016-03-31) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.1.2...v0.1.3) + +## [v0.1.2](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.1.2) (2016-03-25) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.1.1...v0.1.2) + +**Closed issues:** + +- Let attributes that should have underscores through somehow [\#12](https://github.com/JuliaPlots/PlotlyJS.jl/issues/12) +- Implement show properly [\#3](https://github.com/JuliaPlots/PlotlyJS.jl/issues/3) + +## [v0.1.1](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.1.1) (2016-03-11) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/v0.1.0...v0.1.1) + +**Closed issues:** + +- restyle! needs to be fixed... Julia and javascript have different semantics [\#23](https://github.com/JuliaPlots/PlotlyJS.jl/issues/23) +- IJulia notebook export to HTML don't show the plot [\#22](https://github.com/JuliaPlots/PlotlyJS.jl/issues/22) + +**Merged pull requests:** + +- Matching plotly.js semantics in restyle! [\#24](https://github.com/JuliaPlots/PlotlyJS.jl/pull/24) ([sglyon](https://github.com/sglyon)) + +## [v0.1.0](https://github.com/JuliaPlots/PlotlyJS.jl/tree/v0.1.0) (2016-03-05) + +[Full Changelog](https://github.com/JuliaPlots/PlotlyJS.jl/compare/7d69a1c8497429bf579e05dad8da72934eae947d...v0.1.0) + +**Closed issues:** + +- Have display not duplicate plots in windows [\#20](https://github.com/JuliaPlots/PlotlyJS.jl/issues/20) +- Clean up design [\#19](https://github.com/JuliaPlots/PlotlyJS.jl/issues/19) +- Conflict with DataFrames.jl [\#16](https://github.com/JuliaPlots/PlotlyJS.jl/issues/16) +- is collapse\( \) supposed to work with multiple columns? [\#15](https://github.com/JuliaPlots/PlotlyJS.jl/issues/15) +- savefig \(via cairosvg\) doesn't show negative signs in tick labels [\#14](https://github.com/JuliaPlots/PlotlyJS.jl/issues/14) +- Events [\#13](https://github.com/JuliaPlots/PlotlyJS.jl/issues/13) +- Implement `attr` function with kwarg + \_ mini-language [\#11](https://github.com/JuliaPlots/PlotlyJS.jl/issues/11) +- Rename to PlotlyJS.jl [\#9](https://github.com/JuliaPlots/PlotlyJS.jl/issues/9) +- Error showing Plot [\#8](https://github.com/JuliaPlots/PlotlyJS.jl/issues/8) +- Integrate various plotly packages [\#5](https://github.com/JuliaPlots/PlotlyJS.jl/issues/5) +- subplots [\#1](https://github.com/JuliaPlots/PlotlyJS.jl/issues/1) + +**Merged pull requests:** + +- Sl/syncplots [\#21](https://github.com/JuliaPlots/PlotlyJS.jl/pull/21) ([sglyon](https://github.com/sglyon)) +- Add a Gitter chat badge to README.md [\#17](https://github.com/JuliaPlots/PlotlyJS.jl/pull/17) ([gitter-badger](https://github.com/gitter-badger)) +- Tweak JS API use [\#7](https://github.com/JuliaPlots/PlotlyJS.jl/pull/7) ([MikeInnes](https://github.com/MikeInnes)) +- fix Plot\(\) error [\#6](https://github.com/JuliaPlots/PlotlyJS.jl/pull/6) ([tbreloff](https://github.com/tbreloff)) +- Update REQUIRE [\#2](https://github.com/JuliaPlots/PlotlyJS.jl/pull/2) ([cc7768](https://github.com/cc7768)) + + + +\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* diff --git a/PlotlyJS/LICENSE.md b/PlotlyJS/LICENSE.md new file mode 100644 index 0000000..fedff35 --- /dev/null +++ b/PlotlyJS/LICENSE.md @@ -0,0 +1,22 @@ +The Plotly.jl package is licensed under the MIT "Expat" License: + +> Copyright (c) 2015: Spencer Lyon. +> +> Permission is hereby granted, free of charge, to any person obtaining +> a copy of this software and associated documentation files (the +> "Software"), to deal in the Software without restriction, including +> without limitation the rights to use, copy, modify, merge, publish, +> distribute, sublicense, and/or sell copies of the Software, and to +> permit persons to whom the Software is furnished to do so, subject to +> the following conditions: +> +> The above copyright notice and this permission notice shall be +> included in all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +> CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +> TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/PlotlyJS/Project.toml b/PlotlyJS/Project.toml new file mode 100644 index 0000000..f13d217 --- /dev/null +++ b/PlotlyJS/Project.toml @@ -0,0 +1,35 @@ +name = "PlotlyJS" +uuid = "f0f68f2c-4968-5e81-91da-67840de0976a" +authors = ["Spencer Lyon "] +version = "0.18.11" + +[deps] +Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" +Blink = "ad839575-38b3-5650-b840-f874b8c74a25" +DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" +JSExpr = "97c1335a-c9c5-57fe-bc5d-ec35cebe8660" +JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +Kaleido_jll = "f7e6163d-2fa5-5f23-b69c-1db539e41963" +Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5" +REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +Requires = "ae029012-a4dd-5104-9daa-d747884805df" +WebIO = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29" + +[compat] +Blink = "0.12" +JSExpr = "0.5, 1" +JSON = "0.20, 0.21" +PlotlyBase = "0.8.15" +Reexport = "0.2, 1" +Requires = "1.0" +WebIO = "0.8" +julia = "1.3, 1.4, 1.5, 1.6" + +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test"] diff --git a/PlotlyJS/README.md b/PlotlyJS/README.md new file mode 100644 index 0000000..4065c67 --- /dev/null +++ b/PlotlyJS/README.md @@ -0,0 +1,31 @@ +# PlotlyJS + +[_plotlyjs]: https://plot.ly/javascript + +[docs-img]: https://img.shields.io/badge/docs-stable-blue.svg +[docs-url]: http://juliaplots.org/PlotlyJS.jl/stable + +[![][docs-img]][docs-url] +[![Build Status](https://github.com/JuliaPlots/PlotlyJS.jl/actions/workflows/ci-master-workflow.yml/badge.svg)](https://github.com/JuliaPlots/PlotlyJS.jl/actions/workflows/ci-master-workflow.yml) +[![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://julialang.zulipchat.com/#narrow/stream/227176-plotting) + +Julia interface to [plotly.js][_plotlyjs] visualization library. + +This package constructs plotly graphics using all local resources. To interact or save graphics to the Plotly cloud, use the [`Plotly`](https://github.com/plotly/Plotly.jl) package. + +## Installation + +If you have issues building this package because of installation of the MbedTLS package please see [this issue](https://github.com/sglyon/PlotlyJS.jl/issues/83). + +### Jupyterlab + +If you will be using this package from within Jupyterlab, please also install the plotly jupyterlab extension by running: + + +```sh +jupyter labextension install jupyterlab-plotly +``` + +See the [jupyterlab extension documentation](https://jupyterlab.readthedocs.io/en/stable/user/extensions.html) for more details. + + diff --git a/PlotlyJS/appveyor.yml b/PlotlyJS/appveyor.yml new file mode 100644 index 0000000..d6a29e1 --- /dev/null +++ b/PlotlyJS/appveyor.yml @@ -0,0 +1,41 @@ +environment: + matrix: + - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe" + - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe" + - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe" + - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe" + - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe" + - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe" +matrix: + allow_failures: + - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe" + - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe" + +branches: + only: + - master + - /release-.*/ + +notifications: + - provider: Email + on_build_success: false + on_build_failure: false + on_build_status_changed: false + +install: + - ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12" +# Download most recent Julia Windows binary + - ps: (new-object net.webclient).DownloadFile( + $env:JULIA_URL, + "C:\projects\julia-binary.exe") +# Run installer silently, output to C:\projects\julia + - C:\projects\julia-binary.exe /S /D=C:\projects\julia + +build_script: +# Need to convert from shallow to complete for Pkg.clone to work + - IF EXIST .git\shallow (git fetch --unshallow) + - C:\projects\julia\bin\julia -e "versioninfo(); + Pkg.clone(pwd(), \"Plotly\"); Pkg.build(\"Plotly\")" + +test_script: + - C:\projects\julia\bin\julia --check-bounds=yes -e "Pkg.test(\"Plotly\")" diff --git a/PlotlyJS/assets/index.js b/PlotlyJS/assets/index.js new file mode 100644 index 0000000..915b834 --- /dev/null +++ b/PlotlyJS/assets/index.js @@ -0,0 +1,70 @@ +import {contains, filter, has, isNil, type} from 'ramda'; + +export const PlotlyCommands = { + filterEventData: function(gd, eventData, event) { + let filteredEventData; + if (contains(event, ['click', 'hover', 'selected'])) { + const points = []; + + if (isNil(eventData)) { + return null; + } + + /* + * remove `data`, `layout`, `xaxis`, etc + * objects from the event data since they're so big + * and cause JSON stringify ciricular structure errors. + * + * also, pull down the `customdata` point from the data array + * into the event object + */ + const data = gd.data; + + for(let i=0; i < eventData.points.length; i++) { + const fullPoint = eventData.points[i]; + const pointData = filter(function(o) { + return !contains(type(o), ['Object', 'Array']) + }, fullPoint); + if (has('curveNumber', fullPoint) && + has('pointNumber', fullPoint) && + has('customdata', data[pointData.curveNumber]) + ) { + pointData['customdata'] = data[ + pointData.curveNumber + ].customdata[fullPoint.pointNumber]; + } + + // specific to histogram. see https://github.com/plotly/plotly.js/pull/2113/ + if (has('pointNumbers', fullPoint)) { + pointData.pointNumbers = fullPoint.pointNumbers; + } + + points[i] = pointData; + + } + filteredEventData = {points} + } else if (event === 'relayout') { + /* + * relayout shouldn't include any big objects + * it will usually just contain the ranges of the axes like + * "xaxis.range[0]": 0.7715822247381828, + * "xaxis.range[1]": 3.0095292008680063` + */ + filteredEventData = eventData; + } + if (has('range', eventData)) { + filteredEventData.range = eventData.range; + } + if (has('lassoPoints', eventData)) { + filteredEventData.lassoPoints = eventData.lassoPoints; + } + return { + out: filteredEventData, + isnil: isNil(filteredEventData) + }; + } +}; + +export function init(WebIO) { + WebIO.PlotlyCommands = PlotlyCommands; +} diff --git a/PlotlyJS/assets/package.json b/PlotlyJS/assets/package.json new file mode 100644 index 0000000..1ce49ba --- /dev/null +++ b/PlotlyJS/assets/package.json @@ -0,0 +1,23 @@ +{ + "name": "assets", + "version": "1.0.0", + "description": "WebIO.jl support for plotly", + "main": "index.js", + "dependencies": { + "ramda": "^0.24.1" + }, + "devDependencies": { + "clean-webpack-plugin": "^0.1.19", + "webpack": "^4.17.1", + "webpack-cli": "^3.1.0", + "webpack-merge": "^4.1.4" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "webpack-dev-server --open --config webpack.dev.js", + "build": "webpack --config webpack.prod.js" + }, + "keywords": [], + "author": "Spencer Lyon", + "license": "MIT" +} diff --git a/PlotlyJS/assets/plotly_webio.bundle.js b/PlotlyJS/assets/plotly_webio.bundle.js new file mode 100644 index 0000000..420fcf8 --- /dev/null +++ b/PlotlyJS/assets/plotly_webio.bundle.js @@ -0,0 +1 @@ +!function(t,n){if("object"==typeof exports&&"object"==typeof module)module.exports=n();else if("function"==typeof define&&define.amd)define([],n);else{var r=n();for(var e in r)("object"==typeof exports?exports:t)[e]=r[e]}}(window,function(){return function(t){var n={};function r(e){if(n[e])return n[e].exports;var o=n[e]={i:e,l:!1,exports:{}};return t[e].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=t,r.c=n,r.d=function(t,n,e){r.o(t,n)||Object.defineProperty(t,n,{enumerable:!0,get:e})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,n){if(1&n&&(t=r(t)),8&n)return t;if(4&n&&"object"==typeof t&&t&&t.__esModule)return t;var e=Object.create(null);if(r.r(e),Object.defineProperty(e,"default",{enumerable:!0,value:t}),2&n&&"string"!=typeof t)for(var o in t)r.d(e,o,function(n){return t[n]}.bind(null,o));return e},r.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(n,"a",n),n},r.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},r.p="",r(r.s=120)}([function(t,n,r){var e=r(1),o=r(28);t.exports=function(t){return function n(r,u){switch(arguments.length){case 0:return n;case 1:return o(r)?n:e(function(n){return t(r,n)});default:return o(r)&&o(u)?n:o(r)?e(function(n){return t(n,u)}):o(u)?e(function(n){return t(r,n)}):t(r,u)}}}},function(t,n,r){var e=r(28);t.exports=function(t){return function n(r){return 0===arguments.length||e(r)?n:t.apply(this,arguments)}}},function(t,n,r){var e=r(1),o=r(0),u=r(28);t.exports=function(t){return function n(r,i,c){switch(arguments.length){case 0:return n;case 1:return u(r)?n:o(function(n,e){return t(r,n,e)});case 2:return u(r)&&u(i)?n:u(r)?o(function(n,r){return t(n,i,r)}):u(i)?o(function(n,e){return t(r,n,e)}):e(function(n){return t(r,i,n)});default:return u(r)&&u(i)&&u(c)?n:u(r)&&u(i)?o(function(n,r){return t(n,r,c)}):u(r)&&u(c)?o(function(n,r){return t(n,i,r)}):u(i)&&u(c)?o(function(n,e){return t(r,n,e)}):u(r)?e(function(n){return t(n,i,c)}):u(i)?e(function(n){return t(r,n,c)}):u(c)?e(function(n){return t(r,i,n)}):t(r,i,c)}}}},function(t,n,r){var e=r(15),o=r(45);t.exports=function(t,n,r){return function(){if(0===arguments.length)return r();var u=Array.prototype.slice.call(arguments,0),i=u.pop();if(!e(i)){for(var c=0;c=0;)f(n=o[r],t)&&!i(c,n)&&(c[c.length]=n),r-=1;return c}):c(function(t){return Object(t)!==t?[]:Object.keys(t)}))},function(t,n,r){var e=r(2),o=r(9);t.exports=e(o)},function(t,n){t.exports=Array.isArray||function(t){return null!=t&&t.length>=0&&"[object Array]"===Object.prototype.toString.call(t)}},function(t,n){t.exports=function(t){return t&&t["@@transducer/reduced"]?t:{"@@transducer/value":t,"@@transducer/reduced":!0}}},function(t,n,r){var e=r(23),o=r(2);t.exports=o(e("slice",function(t,n,r){return Array.prototype.slice.call(r,t,n)}))},function(t,n,r){var e=r(84);t.exports=function(t,n){return e(n,t,0)>=0}},function(t,n,r){var e=r(1);t.exports=e(function(t){return function(){return t}})},function(t,n,r){var e=r(0);t.exports=e(function(t,n){return n>t?n:t})},function(t,n,r){var e=r(0),o=r(7),u=r(46);t.exports=e(function(t,n){return o(u(t),n)})},function(t,n){t.exports=function(t){return"[object String]"===Object.prototype.toString.call(t)}},function(t,n,r){var e=r(15);t.exports=function(t,n){return function(){var r=arguments.length;if(0===r)return n();var o=arguments[r-1];return e(o)||"function"!=typeof o[t]?n.apply(this,arguments):o[t].apply(o,Array.prototype.slice.call(arguments,0,r-1))}}},function(t,n,r){var e=r(1),o=r(149);t.exports=e(function(t){return o(t,[])})},function(t,n,r){var e=r(0),o=r(22);t.exports=e(function(t,n){var r=t<0?n.length+t:t;return o(n)?n.charAt(r):n[r]})},function(t,n,r){var e=r(0),o=r(35),u=r(5),i=r(24);t.exports=e(function(t,n){return u(t+1,function(){var r=arguments[t];if(null!=r&&o(r[n]))return r[n].apply(r,Array.prototype.slice.call(arguments,0,t));throw new TypeError(i(r)+' does not have a method named "'+n+'"')})})},function(t,n,r){var e=r(0);t.exports=e(function(t,n){for(var r=n,e=0;e=arguments.length)?s=r[a]:(s=arguments[c],c+=1),i[a]=s,o(s)||(f-=1),a+=1}return f<=0?u.apply(this,i):e(f,t(n,i,u))}}},function(t,n){t.exports=function(t,n){for(var r=0,e=n.length,o=Array(e);r0&&(t.hasOwnProperty(0)&&t.hasOwnProperty(t.length-1)))))})},function(t,n,r){var e=r(2);t.exports=e(function(t,n,r){var e={};for(var o in r)e[o]=r[o];return e[t]=n,e})},function(t,n,r){var e=r(0);t.exports=e(function(t,n){switch(t){case 0:return function(){return n.call(this)};case 1:return function(t){return n.call(this,t)};case 2:return function(t,r){return n.call(this,t,r)};case 3:return function(t,r,e){return n.call(this,t,r,e)};case 4:return function(t,r,e,o){return n.call(this,t,r,e,o)};case 5:return function(t,r,e,o,u){return n.call(this,t,r,e,o,u)};case 6:return function(t,r,e,o,u,i){return n.call(this,t,r,e,o,u,i)};case 7:return function(t,r,e,o,u,i,c){return n.call(this,t,r,e,o,u,i,c)};case 8:return function(t,r,e,o,u,i,c,f){return n.call(this,t,r,e,o,u,i,c,f)};case 9:return function(t,r,e,o,u,i,c,f,a){return n.call(this,t,r,e,o,u,i,c,f,a)};case 10:return function(t,r,e,o,u,i,c,f,a,s){return n.call(this,t,r,e,o,u,i,c,f,a,s)};default:throw new Error("First argument to nAry must be a non-negative integer no greater than ten")}})},function(t,n){t.exports=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},function(t,n,r){var e=r(1),o=r(76);t.exports=e(function(t){return o(t.length,t)})},function(t,n,r){var e=r(1),o=r(5);t.exports=e(function(t){return o(t.length,t)})},function(t,n,r){var e=r(1),o=r(22);t.exports=e(function(t){return o(t)?t.split("").reverse().join(""):Array.prototype.slice.call(t,0).reverse()})},function(t,n,r){var e=r(86),o=r(0),u=r(54);t.exports=o(function(t,n){return u(e(t),n)})},function(t,n,r){var e=r(30),o=r(3),u=r(6),i=r(9),c=r(160);t.exports=e(4,[],o([],c,function(t,n,r,e){return i(function(e,o){var i=r(o);return e[i]=t(u(i,e)?e[i]:n,o),e},{},e)}))},function(t,n){t.exports=function(t,n,r){for(var e=0,o=r.length;e=r.length||n<-r.length)return r;var o=(n<0?r.length:0)+n,u=e(r);return u[o]=t(r[o]),u})},function(t,n){t.exports=function(){function t(t){this.f=t}return t.prototype["@@transducer/init"]=function(){throw new Error("init not implemented on XWrap")},t.prototype["@@transducer/result"]=function(t){return t},t.prototype["@@transducer/step"]=function(t,n){return this.f(t,n)},function(n){return new t(n)}}()},function(t,n,r){var e=r(12),o=r(0);t.exports=o(function(t,n){return e(t.length,function(){return t.apply(n,arguments)})})},function(t,n,r){var e=r(6);t.exports=function(){var t=Object.prototype.toString;return"[object Arguments]"===t.call(arguments)?function(n){return"[object Arguments]"===t.call(n)}:function(t){return e("callee",t)}}()},function(t,n,r){var e=r(0);t.exports=e(function(t,n){return t&&n})},function(t,n,r){var e=r(0),o=r(3),u=r(71);t.exports=e(o(["any"],u,function(t,n){for(var r=0;r1){var s=!f(e)&&o(a,e)?e[a]:i(n[1])?[]:{};r=t(Array.prototype.slice.call(n,1),r,s)}if(i(a)&&u(e)){var p=[].concat(e);return p[a]=r,p}return c(a,r,e)})},function(t,n,r){var e=r(1);t.exports=e(function(t){return null==t})},function(t,n,r){var e=r(0),o=r(9),u=r(47),i=r(5),c=r(7);t.exports=e(function(t,n){var r=i(t,n);return i(t,function(){return o(u,c(r,arguments[0]),Array.prototype.slice.call(arguments,1))})})},function(t,n,r){var e=r(32);t.exports=function(t){return function n(r){for(var o,u,i,c=[],f=0,a=r.length;f10)throw new Error("Constructor with greater than ten arguments");return 0===t?function(){return new n}:o(u(t,function(t,r,e,o,u,i,c,f,a,s){switch(arguments.length){case 1:return new n(t);case 2:return new n(t,r);case 3:return new n(t,r,e);case 4:return new n(t,r,e,o);case 5:return new n(t,r,e,o,u);case 6:return new n(t,r,e,o,u,i);case 7:return new n(t,r,e,o,u,i,c);case 8:return new n(t,r,e,o,u,i,c,f);case 9:return new n(t,r,e,o,u,i,c,f,a);case 10:return new n(t,r,e,o,u,i,c,f,a,s)}}))})},function(t,n,r){var e=r(0),o=r(31),u=r(5),i=r(20),c=r(21),f=r(14);t.exports=e(function(t,n){return u(f(i,0,c("length",n)),function(){var r=arguments,e=this;return t.apply(e,o(function(t){return t.apply(e,r)},n))})})},function(t,n,r){var e=r(0);t.exports=e(function(t,n){return null==n||n!=n?t:n})},function(t,n,r){var e=r(18),o=r(0);t.exports=o(function(t,n){for(var r=[],o=0,u=t.length;o=0?n.length-t:0,n)})},function(t,n,r){var e=r(209),o=r(0);t.exports=o(function(t,n){for(var r,o,u=new e,i=[],c=0;c=0;)n=t(r[e],n),e-=1;return n})},function(t,n,r){var e=r(0);t.exports=e(function(t,n){var r,e=Number(n),o=0;if(e<0||isNaN(e))throw new RangeError("n must be a non-negative number");for(r=new Array(e);o=0?e:0);ro?1:0})},function(t,n,r){var e=r(1),o=r(34);t.exports=e(function(t){return o(2,t)})},function(t,n,r){var e=r(0),o=r(35),u=r(69),i=r(36);t.exports=e(function(t,n){return o(t)?function(){return t.apply(this,arguments)&&n.apply(this,arguments)}:i(u)(t,n)})},function(t,n,r){var e=r(37);t.exports=e(function(t){return t.apply(this,Array.prototype.slice.call(arguments,1))})},function(t,n,r){var e=r(0),o=r(140),u=r(7);t.exports=e(function(t,n){return u(t,o(n))})},function(t,n,r){var e=r(141),o=r(32),u=r(9),i=r(4);t.exports=function(t){var n=function(t){return{"@@transducer/init":i.init,"@@transducer/result":function(n){return t["@@transducer/result"](n)},"@@transducer/step":function(n,r){var o=t["@@transducer/step"](n,r);return o["@@transducer/reduced"]?e(o):o}}}(t);return{"@@transducer/init":i.init,"@@transducer/result":function(t){return n["@@transducer/result"](t)},"@@transducer/step":function(t,r){return o(r)?u(n,t,r):u(n,t,[r])}}}},function(t,n){t.exports=function(t){return{"@@transducer/value":t,"@@transducer/reduced":!0}}},function(t,n,r){var e=r(2);t.exports=e(function(t,n,r){if(t>n)throw new Error("min must not be greater than max in clamp(min, max, value)");return rn?n:r})},function(t,n,r){var e=r(78),o=r(1);t.exports=o(function(t){return null!=t&&"function"==typeof t.clone?t.clone():e(t,[],[],!0)})},function(t,n,r){var e=r(1);t.exports=e(function(t){return function(n,r){return t(n,r)?-1:t(r,n)?1:0}})},function(t,n,r){var e=r(36),o=r(80);t.exports=e(o)},function(t,n){t.exports=function(t,n){return function(){return n.call(this,t.apply(this,arguments))}}},function(t,n,r){var e=r(83),o=r(38);t.exports=function(){if(0===arguments.length)throw new Error("composeP requires at least one argument");return e.apply(this,o(arguments))}},function(t,n){t.exports=function(t,n){return function(){var r=this;return t.apply(r,arguments).then(function(t){return n.call(r,t)})}}},function(t,n,r){var e=r(18),o=r(31),u=r(153),i=r(154),c=r(13),f=r(39);t.exports=function t(n,r){var a=function(o){var u=r.concat([n]);return e(o,u)?"":t(o,u)},s=function(t,n){return o(function(n){return u(n)+": "+a(t[n])},n.slice().sort())};switch(Object.prototype.toString.call(n)){case"[object Arguments]":return"(function() { return arguments; }("+o(a,n).join(", ")+"))";case"[object Array]":return"["+o(a,n).concat(s(n,f(function(t){return/^\d+$/.test(t)},c(n)))).join(", ")+"]";case"[object Boolean]":return"object"==typeof n?"new Boolean("+a(n.valueOf())+")":n.toString();case"[object Date]":return"new Date("+(isNaN(n.valueOf())?a(NaN):u(i(n)))+")";case"[object Null]":return"null";case"[object Number]":return"object"==typeof n?"new Number("+a(n.valueOf())+")":1/n==-1/0?"-0":n.toString(10);case"[object String]":return"object"==typeof n?"new String("+a(n.valueOf())+")":u(n);case"[object Undefined]":return"undefined";default:if("function"==typeof n.toString){var p=n.toString();if("[object Object]"!==p)return p}return"{"+s(n,c(n)).join(", ")+"}"}}},function(t,n,r){var e=r(151),o=r(152),u=r(6),i=r(85),c=r(13),f=r(50);t.exports=function t(n,r,a,s){if(i(n,r))return!0;if(f(n)!==f(r))return!1;if(null==n||null==r)return!1;if("function"==typeof n["fantasy-land/equals"]||"function"==typeof r["fantasy-land/equals"])return"function"==typeof n["fantasy-land/equals"]&&n["fantasy-land/equals"](r)&&"function"==typeof r["fantasy-land/equals"]&&r["fantasy-land/equals"](n);if("function"==typeof n.equals||"function"==typeof r.equals)return"function"==typeof n.equals&&n.equals(r)&&"function"==typeof r.equals&&r.equals(n);switch(f(n)){case"Arguments":case"Array":case"Object":if("function"==typeof n.constructor&&"Promise"===o(n.constructor))return n===r;break;case"Boolean":case"Number":case"String":if(typeof n!=typeof r||!i(n.valueOf(),r.valueOf()))return!1;break;case"Date":if(!i(n.valueOf(),r.valueOf()))return!1;break;case"Error":return n.name===r.name&&n.message===r.message;case"RegExp":if(n.source!==r.source||n.global!==r.global||n.ignoreCase!==r.ignoreCase||n.multiline!==r.multiline||n.sticky!==r.sticky||n.unicode!==r.unicode)return!1;break;case"Map":case"Set":if(!t(e(n.entries()),e(r.entries()),a,s))return!1;break;case"Int8Array":case"Uint8Array":case"Uint8ClampedArray":case"Int16Array":case"Uint16Array":case"Int32Array":case"Uint32Array":case"Float32Array":case"Float64Array":case"ArrayBuffer":break;default:return!1}var p=c(n);if(p.length!==c(r).length)return!1;for(var l=a.length-1;l>=0;){if(a[l]===n)return s[l]===r;l-=1}for(a.push(n),s.push(r),l=p.length-1;l>=0;){var h=p[l];if(!u(h,r)||!t(r[h],n[h],a,s))return!1;l-=1}return a.pop(),s.pop(),!0}},function(t,n){t.exports=function(t){for(var n,r=[];!(n=t.next()).done;)r.push(n.value);return r}},function(t,n){t.exports=function(t){var n=String(t).match(/^function (\w*)/);return null==n?"":n[1]}},function(t,n){t.exports=function(t){return'"'+t.replace(/\\/g,"\\\\").replace(/[\b]/g,"\\b").replace(/\f/g,"\\f").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t").replace(/\v/g,"\\v").replace(/\0/g,"\\0").replace(/"/g,'\\"')+'"'}},function(t,n){var r;t.exports=(r=function(t){return(t<10?"0":"")+t},"function"==typeof Date.prototype.toISOString?function(t){return t.toISOString()}:function(t){return t.getUTCFullYear()+"-"+r(t.getUTCMonth()+1)+"-"+r(t.getUTCDate())+"T"+r(t.getUTCHours())+":"+r(t.getUTCMinutes())+":"+r(t.getUTCSeconds())+"."+(t.getUTCMilliseconds()/1e3).toFixed(3).slice(2,5)+"Z"})},function(t,n,r){var e=r(0),o=r(4);t.exports=function(){function t(t,n){this.xf=n,this.f=t}return t.prototype["@@transducer/init"]=o.init,t.prototype["@@transducer/result"]=o.result,t.prototype["@@transducer/step"]=function(t,n){return this.f(n)?this.xf["@@transducer/step"](t,n):t},e(function(n,r){return new t(n,r)})}()},function(t,n,r){var e=r(12),o=r(1),u=r(7),i=r(20),c=r(14);t.exports=o(function(t){var n=c(i,0,u(function(t){return t[0].length},t));return e(n,function(){for(var n=0;no?-1:e0?(this.n-=1,t):this.xf["@@transducer/step"](t,n)},e(function(n,r){return new t(n,r)})}()},function(t,n,r){var e=r(0),o=r(3),u=r(167),i=r(169);t.exports=e(o([],i,u))},function(t,n,r){var e=r(58);t.exports=function(t,n){return e(t=0&&this.i>=this.n?o(r):r},e(function(n,r){return new t(n,r)})}()},function(t,n,r){var e=r(0),o=r(4);t.exports=function(){function t(t,n){this.xf=n,this.pos=0,this.full=!1,this.acc=new Array(t)}return t.prototype["@@transducer/init"]=o.init,t.prototype["@@transducer/result"]=function(t){return this.acc=null,this.xf["@@transducer/result"](t)},t.prototype["@@transducer/step"]=function(t,n){return this.full&&(t=this.xf["@@transducer/step"](t,this.acc[this.pos])),this.store(n),t},t.prototype.store=function(t){this.acc[this.pos]=t,this.pos+=1,this.pos===this.acc.length&&(this.pos=0,this.full=!0)},e(function(n,r){return new t(n,r)})}()},function(t,n,r){var e=r(0),o=r(3),u=r(171),i=r(172);t.exports=e(o([],i,u))},function(t,n){t.exports=function(t,n){for(var r=n.length-1;r>=0&&t(n[r]);)r-=1;return Array.prototype.slice.call(n,0,r+1)}},function(t,n,r){var e=r(0),o=r(9),u=r(4);t.exports=function(){function t(t,n){this.f=t,this.retained=[],this.xf=n}return t.prototype["@@transducer/init"]=u.init,t.prototype["@@transducer/result"]=function(t){return this.retained=null,this.xf["@@transducer/result"](t)},t.prototype["@@transducer/step"]=function(t,n){return this.f(n)?this.retain(t,n):this.flush(t,n)},t.prototype.flush=function(t,n){return t=o(this.xf["@@transducer/step"],t,this.retained),this.retained=[],this.xf["@@transducer/step"](t,n)},t.prototype.retain=function(t,n){return this.retained.push(n),t},e(function(n,r){return new t(n,r)})}()},function(t,n,r){var e=r(1),o=r(3),u=r(95),i=r(96),c=r(10);t.exports=e(o([],u(c),i(c)))},function(t,n,r){var e=r(0),o=r(3),u=r(175);t.exports=e(o(["dropWhile"],u,function(t,n){for(var r=0,e=n.length;r=0;){if(t(n[r]))return n[r];r-=1}}))},function(t,n,r){var e=r(0),o=r(4);t.exports=function(){function t(t,n){this.xf=n,this.f=t}return t.prototype["@@transducer/init"]=o.init,t.prototype["@@transducer/result"]=function(t){return this.xf["@@transducer/result"](this.xf["@@transducer/step"](t,this.last))},t.prototype["@@transducer/step"]=function(t,n){return this.f(n)&&(this.last=n),t},e(function(n,r){return new t(n,r)})}()},function(t,n,r){var e=r(0),o=r(3),u=r(188);t.exports=e(o([],u,function(t,n){for(var r=n.length-1;r>=0;){if(t(n[r]))return r;r-=1}return-1}))},function(t,n,r){var e=r(0),o=r(4);t.exports=function(){function t(t,n){this.xf=n,this.f=t,this.idx=-1,this.lastIdx=-1}return t.prototype["@@transducer/init"]=o.init,t.prototype["@@transducer/result"]=function(t){return this.xf["@@transducer/result"](this.xf["@@transducer/step"](t,this.lastIdx))},t.prototype["@@transducer/step"]=function(t,n){return this.idx+=1,this.f(n)&&(this.lastIdx=this.idx),t},e(function(n,r){return new t(n,r)})}()},function(t,n,r){var e=r(1),o=r(77);t.exports=e(o(!0))},function(t,n,r){var e=r(23),o=r(0);t.exports=o(e("forEach",function(t,n){for(var r=n.length,e=0;en})},function(t,n,r){var e=r(0);t.exports=e(function(t,n){return t>=n})},function(t,n,r){var e=r(0),o=r(6);t.exports=e(o)},function(t,n,r){var e=r(0);t.exports=e(function(t,n){return t in n})},function(t,n,r){var e=r(25);t.exports=e(0)},function(t,n,r){var e=r(2),o=r(5);t.exports=e(function(t,n,r){return o(Math.max(t.length,n.length,r.length),function(){return t.apply(this,arguments)?n.apply(this,arguments):r.apply(this,arguments)})})},function(t,n,r){var e=r(29);t.exports=e(1)},function(t,n,r){var e=r(40);t.exports=e(function(t,n){return n},null)},function(t,n,r){var e=r(0),o=r(84),u=r(15);t.exports=e(function(t,n){return"function"!=typeof n.indexOf||u(n)?o(n,t,0):n.indexOf(t)})},function(t,n,r){var e=r(17);t.exports=e(0,-1)},function(t,n,r){var e=r(41),o=r(2),u=r(55);t.exports=o(function(t,n,r){return u(function(n){return e(t,n,r)},n)})},function(t,n,r){var e=r(2);t.exports=e(function(t,n,r){t=t=0?t:r.length;var e=Array.prototype.slice.call(r,0);return e.splice(t,0,n),e})},function(t,n,r){var e=r(2);t.exports=e(function(t,n,r){return t=t=0?t:r.length,[].concat(Array.prototype.slice.call(r,0,t),n,Array.prototype.slice.call(r,t))})},function(t,n,r){var e=r(18),o=r(0),u=r(55),i=r(42),c=r(61);t.exports=o(function(t,n){var r,o;return t.length>n.length?(r=t,o=n):(r=n,o=t),c(u(i(e)(r),o))})},function(t,n,r){var e=r(18);t.exports=function(){function t(){this._nativeSet="function"==typeof Set?new Set:null,this._items={}}function n(t,n,r){var o,u=typeof t;switch(u){case"string":case"number":return 0===t&&1/t==-1/0?!!r._items["-0"]||(n&&(r._items["-0"]=!0),!1):null!==r._nativeSet?n?(o=r._nativeSet.size,r._nativeSet.add(t),r._nativeSet.size===o):r._nativeSet.has(t):u in r._items?t in r._items[u]||(n&&(r._items[u][t]=!0),!1):(n&&(r._items[u]={},r._items[u][t]=!0),!1);case"boolean":if(u in r._items){var i=t?1:0;return!!r._items[u][i]||(n&&(r._items[u][i]=!0),!1)}return n&&(r._items[u]=t?[!1,!0]:[!0,!1]),!1;case"function":return null!==r._nativeSet?n?(o=r._nativeSet.size,r._nativeSet.add(t),r._nativeSet.size===o):r._nativeSet.has(t):u in r._items?!!e(t,r._items[u])||(n&&r._items[u].push(t),!1):(n&&(r._items[u]=[t]),!1);case"undefined":return!!r._items[u]||(n&&(r._items[u]=!0),!1);case"object":if(null===t)return!!r._items.null||(n&&(r._items.null=!0),!1);default:return(u=Object.prototype.toString.call(t))in r._items?!!e(t,r._items[u])||(n&&r._items[u].push(t),!1):(n&&(r._items[u]=[t]),!1)}}return t.prototype.add=function(t){return!n(t,!0,this)},t.prototype.has=function(t){return n(t,!1,this)},t}()},function(t,n,r){var e=r(41),o=r(2),u=r(62);t.exports=o(function(t,n,r){var o,i;n.length>r.length?(o=n,i=r):(o=r,i=n);for(var c=[],f=0;f=0;){if(u(n[r],t))return r;r-=1}return-1}return n.lastIndexOf(t)})},function(t,n,r){var e=r(1),o=r(43),u=r(25),i=r(57);t.exports=e(function(t){return o(u(t),i(t))})},function(t,n,r){var e=r(1),o=r(74),u=r(43),i=r(27);t.exports=e(function(t){return u(i(t),o(t))})},function(t,n,r){var e=r(1),o=r(33),u=r(43),i=r(46);t.exports=e(function(t){return u(i(t),o(t))})},function(t,n,r){var e=r(0);t.exports=e(function(t,n){return t=0;)u=t(r[e],u[0]),o[e]=u[1],e-=1;return[o,u[0]]})},function(t,n,r){var e=r(0),o=r(9),u=r(13);t.exports=e(function(t,n){return o(function(r,e){return r[e]=t(n[e],e,n),r},{},u(n))})},function(t,n,r){var e=r(0);t.exports=e(function(t,n){return n.match(t)||[]})},function(t,n,r){var e=r(0),o=r(48);t.exports=e(function(t,n){return o(t)?!o(n)||n<1?NaN:(t%n+n)%n:NaN})},function(t,n,r){var e=r(2);t.exports=e(function(t,n,r){return t(r)>t(n)?r:n})},function(t,n,r){var e=r(1),o=r(107);t.exports=e(function(t){var n=t.length;if(0===n)return NaN;var r=2-n%2,e=(n-r)/2;return o(Array.prototype.slice.call(t,0).sort(function(t,n){return tn?1:0}).slice(e,e+r))})},function(t,n,r){var e=r(109),o=r(24);t.exports=e(function(){return o(arguments)})},function(t,n,r){var e=r(63),o=r(0);t.exports=o(function(t,n){return e({},t,n)})},function(t,n,r){var e=r(63),o=r(1);t.exports=o(function(t){return e.apply(null,[{}].concat(t))})},function(t,n,r){var e=r(0),o=r(44);t.exports=e(function(t,n){return o(function(t,n,r){return n},t,n)})},function(t,n,r){var e=r(0),o=r(44);t.exports=e(function(t,n){return o(function(t,n,r){return r},t,n)})},function(t,n,r){var e=r(2),o=r(44);t.exports=e(function(t,n,r){return o(function(n,r,e){return t(r,e)},n,r)})},function(t,n,r){var e=r(2),o=r(64);t.exports=e(function(t,n,r){return o(function(n,r,e){return t(r,e)},n,r)})},function(t,n,r){var e=r(0);t.exports=e(function(t,n){return n0&&t(o(n,r))})},function(t,n,r){var e=r(0);t.exports=e(function(t,n){for(var r={},e=0;eo?1:0})})},function(t,n,r){var e=r(0);t.exports=e(function(t,n){return Array.prototype.slice.call(n,0).sort(function(n,r){for(var e=0,o=0;0===e&&o=0&&t(n[r]);)r-=1;return Array.prototype.slice.call(n,r+1)})},function(t,n,r){var e=r(0),o=r(3),u=r(288);t.exports=e(o(["takeWhile"],u,function(t,n){for(var r=0,e=n.length;risa(_x, AbstractDict), values(d)) + # description and valtype ire empty, but children is not + _desc = pop!(d, :description, "") + desc = isempty(_desc) ? nothing : MD(_desc) + valtype = nothing + filter!(d) do p + !(p[1] in (:_deprecated, :tracerefminus)) && !(startswith(string(p[1]), "_")) + end + kids = Dict{Symbol,SchemaAttribute}() + for (a_k, v) in d + isa(v, AbstractDict) || continue + kids[a_k] = SchemaAttribute(v) + end + children = Dict{Symbol,SchemaAttribute}(kids) + else + valtype = get(d, :valType, nothing) + desc = Markdown.parse(get(d, :description, "")) + + # children is none + children = nothing + end + + flags = valtype == "flaglist" ? d[:flags] : nothing + vals = valtype == "enumerated" ? d[:values] : nothing + + SchemaAttribute(desc, valtype, flags, vals, children) +end + +struct TraceSchema + name::Symbol + description::Union{MD, Nothing} + attributes::Dict{Symbol,SchemaAttribute} +end + +function TraceSchema(nm::Symbol, d::AbstractDict, attrs_key=:attributes) + _attrs = filter!(p -> p[1] != :uid && p[1] != :type, d[attrs_key]) + attrs = Dict{Symbol,SchemaAttribute}() + for (k, v) in _attrs + isa(v, AbstractDict) || continue + attrs[k] = SchemaAttribute(v) + end + desc = get(d, :description, "") + description = isempty(desc) ? MD() : Markdown.parse(desc) + TraceSchema(nm, description, attrs) +end + +struct Schema + traces::Dict{Symbol,TraceSchema} + layout::TraceSchema + + function Schema() + _path = joinpath(artifact"plotly-artifacts", "plot-schema.json") + schema = _symbol_dict(JSON.parse(read(_path, String)))[:schema] + + traces = Dict{Symbol,TraceSchema}() + for (k, v) in schema[:traces] + traces[k] = TraceSchema(k, v) + end + + layout = TraceSchema(:layout, schema[:layout], :layoutAttributes) + new(traces, layout) + end +end + +doc_html(parent::Symbol, name::Symbol, x::Union{SchemaAttribute,TraceSchema}) = + takebuf_string(doc_html!(IOBuffer(), parent, name, x)) + +function doc_html!(buf::IO, parent::Symbol, name::Symbol, sa::SchemaAttribute) + data_parent = "$(parent)_attributes" + id = "$(parent)_$(name)" + print(buf,"
") + print(buf, """ + + """) + println(buf, "
") + + # if we have a description or children, we need a panel-body + has_body = sa.description !== nothing || sa.description !== nothing + + # add in description if we have one + if has_body + print(buf, "
") + end + + if sa.description !== nothing + println(buf, Markdown.html(sa.description)) + end + + if sa.children !== nothing + new_parent = Symbol(string(parent), "_", string(name)) + # need to add panel-group + print(buf, "
") + + # recursively add in children, if any + kids = sa.children + for kid_name in sort!(collect(keys(kids))) + doc_html!(buf, new_parent, kid_name, kids[kid_name]) + end + + # close panel group + println(buf, "
") + end + + # close body div + has_body && println(buf, "
") + + # close outer divs + println(buf, "
") # + println(buf, "
") + buf +end + +function doc_html!(buf::IO, data_parent::Symbol, name::Symbol, ts::TraceSchema) + id = "$(data_parent)_$(name)" + print(buf, """ +
+ ") + + println(buf, "
") + println(buf, "
") + if ts.description !== nothing + println(buf, Markdown.html(ts.description)) + end + + print(buf, "
") + + # now add all attributes + kids = sort!(collect(keys(ts.attributes))) + for kid_name in kids + doc_html!(buf, name, kid_name, ts.attributes[kid_name]) + end + + println(buf, "
") + println(buf, "
") + println(buf, "
") + println(buf, "
") + return buf +end + +doc_html(s::Schema) = takebuf_string(doc_html!(IOBuffer(), s)) + +function doc_html!(buf::IO, s::Schema) + println(buf, + """ + + + + + + + + + """) + + println(buf, + """ +
+

Trace attributes

+
+ """) + + # add traces + for kid_name in sort!(collect(keys(s.traces))) + doc_html!(buf, :traces, kid_name, s.traces[kid_name]) + end + # doc_html!(buf, :traces, :scatter, s.traces[:scatter]) + + println(buf, "
") + println(buf, "
") + + # now do layout + println(buf, + """ +
+

Layout attributes

+
+ """) + doc_html!(buf, :layout, :layout, s.layout) + + println(buf, "
") + println(buf, "
") + println(buf, "") + println(buf, "") + buf +end + +open(joinpath(dirname(@__FILE__), "schema.html"), "w") do f + doc_html!(f, Schema()) +end + +end # module diff --git a/PlotlyJS/docs/.gitignore b/PlotlyJS/docs/.gitignore new file mode 100644 index 0000000..a303fff --- /dev/null +++ b/PlotlyJS/docs/.gitignore @@ -0,0 +1,2 @@ +build/ +site/ diff --git a/PlotlyJS/docs/Project.toml b/PlotlyJS/docs/Project.toml new file mode 100644 index 0000000..5826022 --- /dev/null +++ b/PlotlyJS/docs/Project.toml @@ -0,0 +1,15 @@ +[deps] +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" +Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" +JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5" +PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" +RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" diff --git a/PlotlyJS/docs/build_example_docs.jl b/PlotlyJS/docs/build_example_docs.jl new file mode 100644 index 0000000..7dfb12d --- /dev/null +++ b/PlotlyJS/docs/build_example_docs.jl @@ -0,0 +1,85 @@ +#= +This file takes the code from each file in the examples folder and +creates a markdown file of the same name as the julia file then +puts each example from the julia file into a code block and adds +a short html div below with the interactive output. +=# +using PlotlyJS + +# used in examples +using Distributions, HTTP, DataFrames, RDatasets, Colors, CSV, JSON +using Random, Dates, LinearAlgebra, DelimitedFiles + + +const THIS_DIR = dirname(@__FILE__) + + +# Walk through each example in a file and get the markdown from `single_example` +function single_example_file(filename::String) + base_fn = split(filename, ".")[1] + start_example = "```@example $(base_fn)" + end_example = "```" + # Open a file to write to + open(joinpath(THIS_DIR, "src", "examples", "$(base_fn).md"), "w") do outfile + + write_example(ex) = println(outfile, start_example, "\n", ex, "\n", end_example, "\n") + + fn_h1 = titlecase(replace(base_fn, "_" => " ")) + println(outfile, "# $(fn_h1)\n") + + # Read lines from a files + fulltext = open( + f->read(f, String), + joinpath(THIS_DIR, "..", "examples", filename), + "r" + ) + all_lines = split(fulltext, "\n") + l = 1 + regex = r"^function ([^_].+?)\(" + regex_end = r"^end$" + + # find preamble + if base_fn == "subplots" # special case + preamble = "using PlotlyJS, Dates\ninclude(\"../../../examples/line_scatter.jl\")" + write_example(preamble) + else + first_line = findfirst(x -> match(regex, x) !== nothing, all_lines) + if first_line !== nothing + preamble = strip(join(all_lines[1:first_line-1], "\n")) + write_example(preamble) + end + end + + while true + # Find next function name (break if none) + l = findnext(x -> match(regex, x) !== nothing, all_lines, l+1) + if l == 0 || l === nothing + break + end + # find corresponding end for this function + end_l = findnext(x -> match(regex_end, x) !== nothing, all_lines, l+1) + + # Pull out function text + func_block = join(all_lines[l:end_l], "\n") + fun_name = match(regex, all_lines[l])[1] + # println("adding $fun_name") + an_ex = string(func_block, "\n", fun_name, "()") + write_example(an_ex) + l = end_l + end + end # do outfile + + return nothing +end + +function main() + # Read all file names in + if length(ARGS) == 0 + all_file_names = readdir(joinpath(THIS_DIR, "..", "examples")) + else + all_file_names = [endswith(i, ".jl") ? i : "$(i).jl" for i in ARGS] + end + all_julia_files = filter(x -> endswith(x, ".jl"), all_file_names) + + foreach(single_example_file, all_julia_files) +end diff --git a/PlotlyJS/docs/make.jl b/PlotlyJS/docs/make.jl new file mode 100644 index 0000000..330e052 --- /dev/null +++ b/PlotlyJS/docs/make.jl @@ -0,0 +1,151 @@ +using Documenter +using PlotlyJS +using PlotlyBase + +PlotlyJS.set_default_renderer(PlotlyJS.DOCS) + +const THIS_DIR = dirname(@__FILE__) + +# used in examples +using Distributions, HTTP, DataFrames, RDatasets, Colors, CSV, JSON +using Random, Dates, LinearAlgebra, DelimitedFiles + +# to override display_dict below +# import Documenter.Utilities: display_dict, limitstringmime +# using Base64:stringmime + +# function display_dict(p::PlotlyBase.Plot) +# out = Dict{MIME,Any}() +# # Always generate text/plain +# out[MIME"text/plain"()] = limitstringmime(MIME"text/plain"(), p) +# svg_m = MIME"image/svg+xml"() +# out[svg_m] = stringmime(svg_m, p) +# out +# end + +# display_dict(p::PlotlyJS.SyncPlot) = display_dict(p.plot) + +## handle examples +# Walk through each example in a file and get the markdown from `single_example` +function single_example_file(filename::String) + base_fn = split(filename, ".")[1] + start_example = "```@example $(base_fn)" + end_example = "```" + # Open a file to write to + open(joinpath(THIS_DIR, "src", "examples", "$(base_fn).md"), "w") do outfile + + write_example(ex) = println(outfile, start_example, "\n", ex, "\n", end_example, "\n") + + fn_h1 = titlecase(replace(base_fn, "_" => " ")) + println(outfile, "# $(fn_h1)\n") + + # Read lines from a files + fulltext = open( + f -> read(f, String), + joinpath(THIS_DIR, "..", "examples", filename), + "r" + ) + all_lines = split(fulltext, "\n") + l = 1 + regex = r"^function ([^_].+?)\(" + regex_end = r"^end$" + + # find preamble + if base_fn == "subplots" # special case + preamble = "using PlotlyJS, Dates\ninclude(\"../../../examples/line_scatter.jl\")" + write_example(preamble) + else + first_line = findfirst(x -> match(regex, x) !== nothing, all_lines) + if first_line !== nothing + preamble = strip(join(all_lines[1:first_line - 1], "\n")) + write_example(preamble) + end + end + + while true + # Find next function name (break if none) + l = findnext(x -> match(regex, x) !== nothing, all_lines, l + 1) + if l == 0 || l === nothing + break + end + # find corresponding end for this function + end_l = findnext(x -> match(regex_end, x) !== nothing, all_lines, l + 1) + + # Pull out function text + func_block = join(all_lines[l:end_l], "\n") + fun_name = match(regex, all_lines[l])[1] + # println("adding $fun_name") + an_ex = string(func_block, "\n", fun_name, "()") + write_example(an_ex) + l = end_l + end + end # do outfile + + return nothing +end + +function handle_examples() + @info "Updating examples!" + # Read all file names in + if length(ARGS) == 0 + all_file_names = readdir(joinpath(THIS_DIR, "..", "examples")) + else + all_file_names = [endswith(i, ".jl") ? i : "$(i).jl" for i in ARGS] + end + all_julia_files = filter(x -> endswith(x, ".jl"), all_file_names) + + foreach(single_example_file, all_julia_files) +end + +handle_examples() + +makedocs( + sitename="PlotlyJS", + format=Documenter.HTML( + assets=[ + "include_plotlyjs.js" + ] + ), + modules=[PlotlyJS, PlotlyBase], + linkcheck=true, + pages=[ + "Home" => "index.md", + "User Guide" => [ + "Preliminaries" => "basics.md", + "Building Blocks" => "building_traces_layouts.md", + "Putting it together" => "syncplots.md", + "Working with plots" => "manipulating_plots.md", + "Contributing" => "contributing.md", + ], + "Examples" => [ + "3d" => "examples/3d.md", + "Area" => "examples/area.md", + "Bar" => "examples/bar.md", + "Box Plots" => "examples/box_plots.md", + "Contour" => "examples/contour.md", + "Financial Charts" => "examples/finance.md", + "Heatmaps" => "examples/heatmaps.md", + "Histograms" => "examples/histograms.md", + "Line and Scatter" => "examples/line_scatter.md", + "Maps" => "examples/maps.md", + "Shapes" => "examples/shapes.md", + "Subplots" => "examples/subplots.md", + "Tables" => "examples/tables.md", + "Ternary" => "examples/ternary.md", + "Time Series" => "examples/time_series.md", + "Violin" => "examples/violin.md", + ], + "API Docs" => "api.md" + ] +) + +# Documenter can also automatically deploy documentation to gh-pages. +# See "Hosting Documentation" and deploydocs() in the Documenter manual +# for more information. +#= deploydocs( + repo = "" +) =# + +deploydocs( + repo="github.com/JuliaPlots/PlotlyJS.jl.git", +) diff --git a/PlotlyJS/docs/src/api.md b/PlotlyJS/docs/src/api.md new file mode 100644 index 0000000..5f664f0 --- /dev/null +++ b/PlotlyJS/docs/src/api.md @@ -0,0 +1,6 @@ +# API Documentation + +```@autodocs +Modules = [PlotlyBase, PlotlyJS] +Order = [:function, :type] +``` diff --git a/PlotlyJS/docs/src/assets/include_plotlyjs.js b/PlotlyJS/docs/src/assets/include_plotlyjs.js new file mode 100644 index 0000000..dd69c2a --- /dev/null +++ b/PlotlyJS/docs/src/assets/include_plotlyjs.js @@ -0,0 +1,12 @@ +if (typeof require !== "undefined") { + console.log("Trying to load plotly.js via requirejs"); + require.undef("plotly"); + requirejs.config({ + paths: { + plotly: ["https://cdn.plot.ly/plotly-2.3.0.min"], + }, + }); + require(["plotly"], function (Plotly) { + window._Plotly = Plotly; + }); +} diff --git a/PlotlyJS/docs/src/basics.md b/PlotlyJS/docs/src/basics.md new file mode 100644 index 0000000..94f77f9 --- /dev/null +++ b/PlotlyJS/docs/src/basics.md @@ -0,0 +1,64 @@ +## Basics + +[plotly.js][_plotlyjs] figures are constructed by calling the function: + +```js +Plotly.newPlot(divid, data, layout, config, frames) +``` + +where + +- `divid` is an html `div` element where the plot should appear +- `data` is an array of JSON objects describing the various `trace`s in the visualization +- `layout` is a JSON object describing the layout properties of the visualization. +- `config` is a JSON object describing the configuration properties of the visualization. See more detail [here](https://plotly.com/javascript/configuration-options/) +- `frames` can contain data and layout objects, which define any changes to be animated, and a traces object that defines which traces to animate. + +The `divid` argument is handled automatically by one of the supported +frontends, so users of this package will mostly be concerned about constructing +the `data`, `layout`, and (optionally) `config` and `frames` arguments. + +For a complete list of traces and their attributes see the [plotly.js chart attribute reference][_plotlyref]. + + + +## Julia types + +There are a handful of core Julia types for representing a visualization + +These are + +```julia +abstract type AbstractTrace end +abstract type AbstractLayout end + +mutable struct GenericTrace{T <: AbstractDict{Symbol,Any}} <: AbstractTrace + fields::T +end + +mutable struct Layout{T <: AbstractDict{Symbol,Any}} <: AbstractLayout + fields::T + subplots::_Maybe{Subplots} +end + +mutable struct PlotlyFrame{T <: AbstractDict{Symbol,Any}} <: AbstractPlotlyAttribute + fields::T +end + +mutable struct Plot{TT<:AbstractVector{<:AbstractTrace},TL<:AbstractLayout,TF<:AbstractVector{<:PlotlyFrame}} + data::TT + layout::TL + divid::UUID + config::PlotConfig + frames::TF +end +``` + +The `data`, `layout`, `divid`, `config`, and `frames` fields of the `Plot` type map 1-1 to the arguments to the `Plotly.newplot` function. + + +[_plotlyjs]: https://plotly.com/javascript/ +[_plotlyref]: https://plotly.com/julia/reference/ diff --git a/PlotlyJS/docs/src/building_traces_layouts.md b/PlotlyJS/docs/src/building_traces_layouts.md new file mode 100644 index 0000000..3e1a5f0 --- /dev/null +++ b/PlotlyJS/docs/src/building_traces_layouts.md @@ -0,0 +1,279 @@ +# Building Blocks + +```@setup traces_layous +using PlotlyJS, JSON +``` + +Recall that the `Plotly.newPlot` javascript function expects to receive an +array of `trace` objects and, optionally, a `layout` object. In this section we +will learn how to build these object in Julia. + +## Traces + +A `Plot` instance will have a vector of `trace`s. These should each be a subtype of `AbstractTrace`. + +PlotlyJS.jl defines one such subtype: + +```julia +mutable struct GenericTrace{T <: AbstractDict{Symbol,Any}} <: AbstractTrace + fields::T +end +``` + +The `fields` is an AbstractDict object that maps trace attributes to their values. + +We create this wrapper around a Dict to provide some convnient syntax as described below. + +Let's consider an example. Suppose we would like to build the following JSON +object: + +```json +{ + "type": "scatter", + "x": [1, 2, 3, 4, 5], + "y": [1, 6, 3, 6, 1], + "mode": "markers+text", + "name": "Team A", + "text": ["A-1", "A-2", "A-3", "A-4", "A-5"], + "textposition": "top center", + "textfont": { + "family": "Raleway, sans-serif" + }, + "marker": { "size": 12 } +} +``` + +One way to do this in Julia is: + +```@example traces_layous +fields = Dict{Symbol,Any}(:type => "scatter", + :x => [1, 2, 3, 4, 5], + :y => [1, 6, 3, 6, 1], + :mode => "markers+text", + :name => "Team A", + :text => ["A-1", "A-2", "A-3", "A-4", "A-5"], + :textposition => "top center", + :textfont => Dict(:family => "Raleway, sans-serif"), + :marker => Dict(:size => 12)) +GenericTrace("scatter", fields) +``` + +A more convenient syntax is: + +```@setup traces_layous +using PlotlyJS, JSON +``` + +```@example traces_layous +t1 = scatter(;x=[1, 2, 3, 4, 5], + y=[1, 6, 3, 6, 1], + mode="markers+text", + name="Team A", + text=["A-1", "A-2", "A-3", "A-4", "A-5"], + textposition="top center", + textfont_family="Raleway, sans-serif", + marker_size=12) +``` + +Notice a few things: + +- The trace `type` became the function name. There is a similar method for all +plotly.js traces types. +- All other trace attributes were set using keyword arguments. This allows us +to avoid typing out the symbol prefix (`:`) and the arrows (`=>`) that were +necessary when constructing the `Dict` +- We can set nested attributes using underscores. Notice that the JSON +`"marker": { "size": 12 }` was written `marker_size=12`. + +We can verify that this is indeed equivalent JSON by printing the JSON: (note the order of the attributes is different, but the content is identical): + +```@example traces_layous +print(JSON.json(t1, 2)) +``` + +### Accessing attributes + +If we then wanted to extract a particular attribute, we can do so using +`getindex(t1, :attrname)`, or the syntactic sugar `t1[:attrname]`. Note that +both symbols and strings can be used in a call to `getindex`: + +```@repl traces_layous +t1["marker"] +t1[:marker] +``` + +To access a nested property use `parent.child` + +```@repl traces_layous +t1["textfont.family"] +``` + +### Setting additional attributes + +We can also set additional attributes. Suppose we wanted to set `marker.color` +to be red. We can do this with a call to `setindex!(t1, "red", :marker_color)`, +or equivalently `t1["marker_color"] = "red"`: + +```@repl traces_layous +t1["marker_color"] = "red" + +println(JSON.json(t1, 2)) +``` + +Notice how the `color` attribute was correctly added within the existing +`marker` attribute (alongside `size`), instead of replacing the `marker` +attribute. + +You can also use this syntax to add completely new nested attributes: + +```@repl traces_layous +t1["line_width"] = 5 +println(JSON.json(t1, 2)) +``` + +## Layouts + +The `Layout` type is defined as + +```julia +mutable struct Layout{T <: AbstractDict{Symbol,Any}} <: AbstractLayout + fields::T + subplots::_Maybe{Subplots} +end +``` + +You can construct a layout using the same convenient keyword argument syntax +that we used for traces: + +```@repl traces_layous +l = Layout(;title="Penguins", + xaxis_range=[0, 42.0], xaxis_title="fish", + yaxis_title="Weight", + xaxis_showgrid=true, yaxis_showgrid=true, + legend_y=1.15, legend_x=0.7) +println(JSON.json(l, 2)) +``` + +## `attr` + +There is a special function named `attr` that allows you to apply the same +keyword magic we saw in the trace and layout functions, but to nested +attributes. Let's revisit the previous example, but use `attr` to build up our +`xaxis` and `legend`: + +```@repl traces_layous +l2 = Layout(;title="Penguins", + xaxis=attr(range=[0, 42.0], title="fish", showgrid=true), + yaxis_title="Weight", yaxis_showgrid=true, + legend=attr(x=0.7, y=1.15)) +println(JSON.json(l2, 2)) +``` + +Notice we got the exact same output as before, but we didn't have to resort to +building the `Dict` by hand _or_ prefixing multiple arguments with `xaxis_` or +`legend_`. + + +## Using `DataFrame`s + +!!! note + New in version 0.6.0 + +You can also construct traces using the columns of any subtype of +`AbstractDataFrame` (e.g. the `DataFrame` type from DataFrames.jl). + +To demonstrate this functionality let's load the famous iris data set: + +```@repl traces_layous +using DataFrames, RDatasets +iris = dataset("datasets", "iris"); +first(iris, 10) +``` + +Suppose that we wanted to construct a scatter trace with the `SepalLength` +column as the x variable and the `SepalWidth` columns as the y variable. We +do this by calling + +```@repl traces_layous +my_trace = scatter(iris, x=:SepalLength, y=:SepalWidth, marker_color=:red) +[my_trace[:x][1:5] my_trace[:y][1:5]] +my_trace[:marker_color] +``` + +How does this work? The basic rule is that if the value of any keyword argument +is a Julia Symbol (i.e. created with `:something`), then the function creating +the trace checks if that symbol is one of the column names in the DataFrame. +If so, it extracts the column from the DataFrame and sets that as the value +for the keyword argument. Otherwise it passes the symbol directly through. + +In the above example, when we constructed `my_trace` the value of the keyword +argument `x` was set to the Symbol `:SepalLength`. This did match a column name +from `iris` so that column was extracted and replaced `:SepalLength` as the +value for the `x` argument. The same holds for `y` and `SepalWidth`. + +However, when setting `marker_color=:red` we found that `:red` is not one of +the column names, so the value for the `marker_color` keyword argument remained +`:red`. + +The DataFrame interface becomes more useful when constructing whole plots. See +the [convenience methods](@ref constructors) section of the +documentation for more information. + +!!! note + New in version 0.9.0 + +As of version 0.9.0, you can construct groups of traces using the DataFrame +api. This is best understood by example, so let's see it in action: + +```@repl traces_layous +iris = dataset("datasets", "iris"); +unique(iris[:Species]) +traces = scatter( + iris, group=:Species, x=:SepalLength, y=:SepalWidth, mode="markers", marker_size=8 +) +[t[:name] for t in traces] +``` + +Notice how there are three `Species` in the `iris` DataFrame, and when passing +`group=:Species` to `scatter` we obtained three traces. + +We can pass a `Vector{Symbol}` as group, to split the data on the value in more +than one column: + +```@repl traces_layous +tips = dataset("reshape2", "tips"); +unique(tips[:Sex]) +unique(tips[:Day]) +traces = violin(tips, group=[:Sex, :Day], x=:TotalBill, orientation="h") +[t[:name] for t in traces] +``` + +Also new in version 0.9.0, when using the DataFrame API you are allowed to pass +a function as the value for a keyword argument. When the each trace is +constructed, the value will be replaced by calling the function on whatever +DataFrame is being used. When used in conjunction with the `group` argument, +this allows you to _compute_ group specific trace attributes on the fly. + +See the docstring for `GenericTrace` and the `violin_side_by_side` example on +the [Violin](@ref) example page more details. + +### Facets + +!!! note + New in PlotlyBase version 0.6.5 (PlotlyJS version 0.16.4) + +When plotting a `DataFrame` (let's call it `df`), the keyword arguments `facet_row` and `facet_col` allow you to create a matrix of subplots. The rows of this matrix correspond `unique(df[:facet_row])`, where `:facet_row` is a placeholder for the actual value passed as the `facet_row` argument. Similarly, the columns of the matrix of subplots come from `unique(df[:facet_col])`. + +Each subplot will have the same structure, as defined by the keyword arguments passed to `plot`, but will only show data for a single value of `facet_row` and `facet_col` at a time. + +Below is an example of how this works + +```@repl facets +using PlotlyJS, CSV, DataFrames +df = dataset(DataFrame, "tips") + +plot( + df, x=:total_bill, y=:tip, xbingroyp="x", ybingroup="y", kind="histogram2d", + facet_row=:sex, facet_col=:smoker +) +``` diff --git a/PlotlyJS/docs/src/contributing.md b/PlotlyJS/docs/src/contributing.md new file mode 100644 index 0000000..a6d8113 --- /dev/null +++ b/PlotlyJS/docs/src/contributing.md @@ -0,0 +1,59 @@ +## Contributing + +Contributions are welcome! For a quick list at the things on our radar, check +out the [issue list](https://github.com/JuliaPlots/PlotlyJS.jl/issues). + +If submitting pull requests on GitHub is intimidating, we're happy to help you +work through getting your code polished up and included in the right places. + +Other projects that are helpful are: + +- Adding docstrings to function names +- Adding more examples to the documentation (see below) +- Submitting feature requests or bug reports + +### Documentation + +The documentation for `PlotlyJS.jl` is contained in the `docs` directory of this +repository. + +Docs are build using the `Documenter.jl` package and can be built following these steps: + +1. Change into the `docs` directory +2. Start julia +3. Activate the docs project by entering package mode (`]`) and then running `activate .` +4. Execute `include("make.jl")` from the Julia prompt + +#### Adding Examples + +tl;dr: adding examples to the docs is as easy as 1, 2, 3... + +1. Add a new function that returns a SyncPlot to a Julia (`.jl`) file in the + `examples` directory +2. Run the Julia script `docs/build_example_docs.jl` to re-generate the markdown + source for the examples section of the docs +3. Rebuild the site using one of the instructions above + +One of the most helpful things users can do to contribute to the documentation +is to add more examples. These are automatically generated from the Julia +(`.jl`) files in the `examples` directory. To add a new example, you simply need +to open one of the files in that directory and add a new 0 argument function +that constructs and returns a `SyncPlot` object (this is the output of the +`plot` function). + +For example, if we wanted to add an example of a scatter plot of the sin function we could add the following function definition inside the `examples/line_scatter.jl` file: + +```julia +function sin_scatter() + x = range(0, stop=2*pi, length=50) + y = sin(x) + plot(scatter(x=x, y=y, marker_symbol="line-nw", mode="markers+symbols")) +end +``` + +The next step is to have Julia re-build the markdown (`.md`) files in +`docs/examples` to use all your new functions in the Julia files from the +`examples` folder. To do this run the script `docs/build_example_docs.jl`. If I +were in the root directory of the repository, I could do this by running `julia docs/build_example_docs.jl`. + +The final step is to build the docs again using one of the commands from above. diff --git a/PlotlyJS/docs/src/examples/3d.md b/PlotlyJS/docs/src/examples/3d.md new file mode 100644 index 0000000..a0b804d --- /dev/null +++ b/PlotlyJS/docs/src/examples/3d.md @@ -0,0 +1,267 @@ +# 3D + +```@example 3d +using PlotlyJS, DataFrames, RDatasets, Colors, Distributions, LinearAlgebra +``` + +```@example 3d +function random_line() + n = 400 + rw() = cumsum(randn(n)) + trace1 = scatter3d(;x=rw(),y=rw(), z=rw(), mode="lines", + marker=attr(color="#1f77b4", size=12, symbol="circle", + line=attr(color="rgb(0,0,0)", width=0)), + line=attr(color="#1f77b4", width=1)) + trace2 = scatter3d(;x=rw(),y=rw(), z=rw(), mode="lines", + marker=attr(color="#9467bd", size=12, symbol="circle", + line=attr(color="rgb(0,0,0)", width=0)), + line=attr(color="rgb(44, 160, 44)", width=1)) + trace3 = scatter3d(;x=rw(),y=rw(), z=rw(), mode="lines", + marker=attr(color="#bcbd22", size=12, symbol="circle", + line=attr(color="rgb(0,0,0)", width=0)), + line=attr(color="#bcbd22", width=1)) + layout = Layout(autosize=false, width=500, height=500, + margin=attr(l=0, r=0, b=0, t=65)) + plot([trace1, trace2, trace3], layout) +end +random_line() +``` + +```@example 3d +function topo_surface() + z = Vector[[27.80985, 49.61936, 83.08067, 116.6632, 130.414, 150.7206, 220.1871, + 156.1536, 148.6416, 203.7845, 206.0386, 107.1618, 68.36975, 45.3359, + 49.96142, 21.89279, 17.02552, 11.74317, 14.75226, 13.6671, 5.677561, + 3.31234, 1.156517, -0.147662], + [27.71966, 48.55022, 65.21374, 95.27666, 116.9964, 133.9056, 152.3412, + 151.934, 160.1139, 179.5327, 147.6184, 170.3943, 121.8194, 52.58537, + 33.08871, 38.40972, 44.24843, 69.5786, 4.019351, 3.050024, 3.039719, + 2.996142, 2.967954, 1.999594], + [30.4267, 33.47752, 44.80953, 62.47495, 77.43523, 104.2153, 102.7393, 137.0004, + 186.0706, 219.3173, 181.7615, 120.9154, 143.1835, 82.40501, 48.47132, + 74.71461, 60.0909, 7.073525, 6.089851, 6.53745, 6.666096, 7.306965, 5.73684, + 3.625628], + [16.66549, 30.1086, 39.96952, 44.12225, 59.57512, 77.56929, 106.8925, + 166.5539, 175.2381, 185.2815, 154.5056, 83.0433, 62.61732, 62.33167, + 60.55916, 55.92124, 15.17284, 8.248324, 36.68087, 61.93413, 20.26867, + 68.58819, 46.49812, 0.2360095], + [8.815617, 18.3516, 8.658275, 27.5859, 48.62691, 60.18013, 91.3286, + 145.7109, 116.0653, 106.2662, 68.69447, 53.10596, 37.92797, 47.95942, + 47.42691, 69.20731, 44.95468, 29.17197, 17.91674, 16.25515, 14.65559, + 17.26048, 31.22245, 46.71704], + [6.628881, 10.41339, 24.81939, 26.08952, 30.1605, 52.30802, 64.71007, + 76.30823, 84.63686, 99.4324, 62.52132, 46.81647, 55.76606, 82.4099, + 140.2647, 81.26501, 56.45756, 30.42164, 17.28782, 8.302431, 2.981626, + 2.698536, 5.886086, 5.268358], + [21.83975, 6.63927, 18.97085, 32.89204, 43.15014, 62.86014, 104.6657, + 130.2294, 114.8494, 106.9873, 61.89647, 55.55682, 86.80986, 89.27802, + 122.4221, 123.9698, 109.0952, 98.41956, 77.61374, 32.49031, 14.67344, + 7.370775, 0.03711011, 0.6423392], + [53.34303, 26.79797, 6.63927, 10.88787, 17.2044, 56.18116, 79.70141, + 90.8453, 98.27675, 80.87243, 74.7931, 75.54661, 73.4373, 74.11694, 68.1749, + 46.24076, 39.93857, 31.21653, 36.88335, 40.02525, 117.4297, 12.70328, + 1.729771, 0], + [25.66785, 63.05717, 22.1414, 17.074, 41.74483, 60.27227, 81.42432, 114.444, + 102.3234, 101.7878, 111.031, 119.2309, 114.0777, 110.5296, 59.19355, + 42.47175, 14.63598, 6.944074, 6.944075, 27.74936, 0, 0, 0.09449376, 0.07732264], + [12.827, 69.20554, 46.76293, 13.96517, 33.88744, 61.82613, 84.74799, + 121.122, 145.2741, 153.1797, 204.786, 227.9242, 236.3038, 228.3655, + 79.34425, 25.93483, 6.944074, 6.944074, 6.944075, 7.553681, 0, 0, 0, 0], + [0, 68.66396, 59.0435, 33.35762, 47.45282, 57.8355, 78.91689, 107.8275, + 168.0053, 130.9597, 212.5541, 165.8122, 210.2429, 181.1713, 189.7617, + 137.3378, 84.65395, 8.677168, 6.956576, 8.468093, 0, 0, 0, 0], + [0, 95.17499, 80.03818, 59.89862, 39.58476, 50.28058, 63.81641, 80.61302, + 66.37824, 198.7651, 244.3467, 294.2474, 264.3517, 176.4082, 60.21857, + 77.41475, 53.16981, 56.16393, 6.949235, 7.531059, 3.780177, 0, 0, 0], + [0, 134.9879, 130.3696, 96.86325, 75.70494, 58.86466, 57.20374, 55.18837, + 78.128, 108.5582, 154.3774, 319.1686, 372.8826, 275.4655, 130.2632, 54.93822, + 25.49719, 8.047439, 8.084393, 5.115252, 5.678269, 0, 0, 0], + [0, 48.08919, 142.5558, 140.3777, 154.7261, 87.9361, 58.11092, 52.83869, + 67.14822, 83.66798, 118.9242, 150.0681, 272.9709, 341.1366, 238.664, 190.2, + 116.8943, 91.48672, 14.0157, 42.29277, 5.115252, 0, 0, 0], + [0, 54.1941, 146.3839, 99.48143, 96.19411, 102.9473, 76.14089, 57.7844, + 47.0402, 64.36799, 84.23767, 162.7181, 121.3275, 213.1646, 328.482, + 285.4489, 283.8319, 212.815, 164.549, 92.29631, 7.244015, 1.167, 0, 0], + [0, 6.919659, 195.1709, 132.5253, 135.2341, 89.85069, 89.45549, 60.29967, + 50.33806, 39.17583, 59.06854, 74.52159, 84.93402, 187.1219, 123.9673, + 103.7027, 128.986, 165.1283, 249.7054, 95.39966, 10.00284, 2.39255, 0, 0], + [0, 21.73871, 123.1339, 176.7414, 158.2698, 137.235, 105.3089, 86.63255, 53.11591, + 29.03865, 30.40539, 39.04902, 49.23405, 63.27853, 111.4215, 101.1956, + 40.00962, 59.84565, 74.51253, 17.06316, 2.435141, 2.287471, -0.0003636982, 0], + [0, 0, 62.04672, 136.3122, 201.7952, 168.1343, 95.2046, 58.90624, 46.94091, + 49.27053, 37.10416, 17.97011, 30.93697, 33.39257, 44.03077, 55.64542, + 78.22423, 14.42782, 9.954997, 7.768213, 13.0254, 21.73166, 2.156372, + 0.5317867], + [0, 0, 79.62993, 139.6978, 173.167, 192.8718, 196.3499, 144.6611, 106.5424, + 57.16653, 41.16107, 32.12764, 13.8566, 10.91772, 12.07177, 22.38254, + 24.72105, 6.803666, 4.200841, 16.46857, 15.70744, 33.96221, 7.575688, + -0.04880907], + [0, 0, 33.2664, 57.53643, 167.2241, 196.4833, 194.7966, 182.1884, 119.6961, + 73.02113, 48.36549, 33.74652, 26.2379, 16.3578, 6.811293, 6.63927, 6.639271, + 8.468093, 6.194273, 3.591233, 3.81486, 8.600739, 5.21889, 0], + [0, 0, 29.77937, 54.97282, 144.7995, 207.4904, 165.3432, 171.4047, 174.9216, + 100.2733, 61.46441, 50.19171, 26.08209, 17.18218, 8.468093, 6.63927, + 6.334467, 6.334467, 5.666687, 4.272203, 0, 0, 0, 0], + [0, 0, 31.409, 132.7418, 185.5796, 121.8299, 185.3841, 160.6566, 116.1478, + 118.1078, 141.7946, 65.56351, 48.84066, 23.13864, 18.12932, 10.28531, + 6.029663, 6.044627, 5.694764, 3.739085, 3.896037, 0, 0, 0], + [0, 0, 19.58994, 42.30355, 96.26777, 187.1207, 179.6626, 221.3898, 154.2617, + 142.1604, 148.5737, 67.17937, 40.69044, 39.74512, 26.10166, 14.48469, + 8.65873, 3.896037, 3.571392, 3.896037, 3.896037, 3.896037, 1.077756, 0], + [0.001229679, 3.008948, 5.909858, 33.50574, 104.3341, 152.2165, 198.1988, + 191.841, 228.7349, 168.1041, 144.2759, 110.7436, 57.65214, 42.63504, + 27.91891, 15.41052, 8.056102, 3.90283, 3.879774, 3.936718, 3.968634, + 0.1236256, 3.985531, -0.1835741], + [0, 5.626141, 7.676256, 63.16226, 45.99762, 79.56688, 227.311, 203.9287, + 172.5618, 177.1462, 140.4554, 123.9905, 110.346, 65.12319, 34.31887, + 24.5278, 9.561069, 3.334991, 5.590495, 5.487353, 5.909499, 5.868994, + 5.833817, 3.568177]] + trace = surface(z=z) + layout = Layout(title="Mt. Bruno Elevation", autosize=false, width=500, + height=500, margin=attr(l=65, r=50, b=65, t=90)) + plot(trace, layout) +end +topo_surface() +``` + +```@example 3d +function multiple_surface() + z1 = Vector[[8.83, 8.89, 8.81, 8.87, 8.9, 8.87], + [8.89, 8.94, 8.85, 8.94, 8.96, 8.92], + [8.84, 8.9, 8.82, 8.92, 8.93, 8.91], + [8.79, 8.85, 8.79, 8.9, 8.94, 8.92], + [8.79, 8.88, 8.81, 8.9, 8.95, 8.92], + [8.8, 8.82, 8.78, 8.91, 8.94, 8.92], + [8.75, 8.78, 8.77, 8.91, 8.95, 8.92], + [8.8, 8.8, 8.77, 8.91, 8.95, 8.94], + [8.74, 8.81, 8.76, 8.93, 8.98, 8.99], + [8.89, 8.99, 8.92, 9.1, 9.13, 9.11], + [8.97, 8.97, 8.91, 9.09, 9.11, 9.11], + [9.04, 9.08, 9.05, 9.25, 9.28, 9.27], + [9, 9.01, 9, 9.2, 9.23, 9.2], + [8.99, 8.99, 8.98, 9.18, 9.2, 9.19], + [8.93, 8.97, 8.97, 9.18, 9.2, 9.18]] + z2 = map(x -> x .+ 1, z1) + z3 = map(x -> x .- 1, z1) + trace1 = surface(z=z1, colorscale="Viridis") + trace2 = surface(z=z2, showscale=false, opacity=0.9, colorscale="Viridis") + trace3 = surface(z=z3, showscale=false, opacity=0.9, colorscale="Viridis") + plot([trace1, trace2, trace3]) +end +multiple_surface() +``` + +```@example 3d +function clustering_alpha_shapes() + # load data + iris = RDatasets.dataset("datasets", "iris") + nms = unique(iris.Species) + colors = [RGB(0.89, 0.1, 0.1), RGB(0.21, 0.50, 0.72), RGB(0.28, 0.68, 0.3)] + + data = GenericTrace[] + + for (i, nm) in enumerate(nms) + df = iris[iris[!, :Species] .== nm, :] + x = df[!, :SepalLength] + y = df[!, :SepalWidth] + z = df[!, :PetalLength] + trace = scatter3d(;name=nm, mode="markers", + marker_size=3, marker_color=colors[i], marker_line_width=0, + x=x, y=y, z=z) + push!(data, trace) + + cluster = mesh3d(;color=colors[i], opacity=0.3, x=x, y=y, z=z) + push!(data, cluster) + end + + # notice the nested attrs to create complex JSON objects + layout = Layout(width=800, height=550, autosize=false, title="Iris dataset", + scene=attr(xaxis=attr(gridcolor="rgb(255, 255, 255)", + zerolinecolor="rgb(255, 255, 255)", + showbackground=true, + backgroundcolor="rgb(230, 230,230)"), + yaxis=attr(gridcolor="rgb(255, 255, 255)", + zerolinecolor="rgb(255, 255, 255)", + showbackground=true, + backgroundcolor="rgb(230, 230,230)"), + zaxis=attr(gridcolor="rgb(255, 255, 255)", + zerolinecolor="rgb(255, 255, 255)", + showbackground=true, + backgroundcolor="rgb(230, 230,230)"), + aspectratio=attr(x=1, y=1, z=0.7), + aspectmode="manual")) + plot(data, layout) +end +clustering_alpha_shapes() +``` + +```@example 3d +function scatter_3d() + Σ = fill(0.5, 3, 3) + Diagonal([0.5, 0.5, 0.5]) + obs1 = rand(MvNormal(zeros(3), Σ), 200)' + obs2 = rand(MvNormal(zeros(3), 0.5Σ), 100)' + + trace1 = scatter3d(;x=obs1[:, 1], y=obs1[:, 2], z=obs1[:, 3], + mode="markers", opacity=0.8, + marker_size=12, marker_line_width=0.5, + marker_line_color="rgba(217, 217, 217, 0.14)") + + trace2 = scatter3d(;x=obs2[:, 1], y=obs2[:, 2], z=obs2[:, 3], + mode="markers", opacity=0.9, + marker=attr(color="rgb(127, 127, 127)", + symbol="circle", line_width=1.0, + line_color="rgb(204, 204, 204)")) + + layout = Layout(margin=attr(l=0, r=0, t=0, b=0)) + + plot([trace1, trace2], layout) +end +scatter_3d() +``` + +```@example 3d +function trisurf() + facecolor = repeat([ + "rgb(50, 200, 200)", + "rgb(100, 200, 255)", + "rgb(150, 200, 115)", + "rgb(200, 200, 50)", + "rgb(230, 200, 10)", + "rgb(255, 140, 0)" + ], inner=[2]) + + t = mesh3d( + x=[0, 0, 1, 1, 0, 0, 1, 1], + y=[0, 1, 1, 0, 0, 1, 1, 0], + z=[0, 0, 0, 0, 1, 1, 1, 1], + i=[7, 0, 0, 0, 4, 4, 2, 6, 4, 0, 3, 7], + j=[3, 4, 1, 2, 5, 6, 5, 5, 0, 1, 2, 2], + k=[0, 7, 2, 3, 6, 7, 1, 2, 5, 5, 7, 6], + facecolor=facecolor) + + plot(t) +end +trisurf() +``` + +```@example 3d +function meshcube() + t = mesh3d( + x=[0, 0, 1, 1, 0, 0, 1, 1], + y=[0, 1, 1, 0, 0, 1, 1, 0], + z=[0, 0, 0, 0, 1, 1, 1, 1], + i=[7, 0, 0, 0, 4, 4, 6, 6, 4, 0, 3, 2], + j=[3, 4, 1, 2, 5, 6, 5, 2, 0, 1, 6, 3], + k=[0, 7, 2, 3, 6, 7, 1, 1, 5, 5, 7, 6], + intensity=range(0, stop=1, length=8), + colorscale=[ + [0, "rgb(255, 0, 255)"], + [0.5, "rgb(0, 255, 0)"], + [1, "rgb(0, 0, 255)"] + ] + ) + plot(t) +end +meshcube() +``` + diff --git a/PlotlyJS/docs/src/examples/area.md b/PlotlyJS/docs/src/examples/area.md new file mode 100644 index 0000000..327cb48 --- /dev/null +++ b/PlotlyJS/docs/src/examples/area.md @@ -0,0 +1,46 @@ +# Area + +```@example area +using PlotlyJS +``` + +```@example area +function area1() + trace1 = scatter(;x=1:4, y=[0, 2, 3, 5], fill="tozeroy") + trace2 = scatter(;x=1:4, y=[3, 5, 1, 7], fill="tonexty") + plot([trace1, trace2]) +end +area1() +``` + +```@example area +function area2() + function _stacked_area!(traces) + for (i, tr) in enumerate(traces[2:end]) + for j in 1:min(length(traces[i]["y"]), length(tr["y"])) + tr["y"][j] += traces[i]["y"][j] + end + end + traces + end + + traces = [scatter(;x=1:3, y=[2, 1, 4], fill="tozeroy"), + scatter(;x=1:3, y=[1, 1, 2], fill="tonexty"), + scatter(;x=1:3, y=[3, 0, 2], fill="tonexty")] + _stacked_area!(traces) + + plot(traces, Layout(title="stacked and filled line chart")) +end +area2() +``` + +```@example area +function area3() + trace1 = scatter(;x=1:4, y=[0, 2, 3, 5], fill="tozeroy", mode="none") + trace2 = scatter(;x=1:4, y=[3, 5, 1, 7], fill="tonexty", mode="none") + plot([trace1, trace2], + Layout(title="Overlaid Chart Without Boundary Lines")) +end +area3() +``` + diff --git a/PlotlyJS/docs/src/examples/bar.md b/PlotlyJS/docs/src/examples/bar.md new file mode 100644 index 0000000..4e8b01c --- /dev/null +++ b/PlotlyJS/docs/src/examples/bar.md @@ -0,0 +1,262 @@ +# Bar + +```@example bar +using PlotlyJS +``` + +```@example bar +function bar1() + data = bar(;x=["giraffes", "orangutans", "monkeys"], + y=[20, 14, 23]) + plot(data) +end +bar1() +``` + +```@example bar +function bar2() + trace1 = bar(;x=["giraffes", "orangutans", "monkeys"], + y=[20, 14, 23], + name="SF Zoo") + trace2 = bar(;x=["giraffes", "orangutans", "monkeys"], + y=[12, 18, 29], + name="LA Zoo") + data = [trace1, trace2] + layout = Layout(;barmode="group") + plot(data, layout) +end +bar2() +``` + +```@example bar +function bar3() + trace1 = bar(;x=["giraffes", "orangutans", "monkeys"], + y=[20, 14, 23], + name="SF Zoo") + trace2 = bar(x=["giraffes", "orangutans", "monkeys"], + y=[12, 18, 29], + name="LA Zoo") + data = [trace1, trace2] + layout = Layout(;barmode="stack") + plot(data, layout) +end +bar3() +``` + +```@example bar +function bar4() + data = bar(;x=["Product A", "Product B", "Product C"], + y=[20, 14, 23], + text=["$(i)% market share" for i in rand(15:30, 3)], + marker=attr(color="rgb(158, 202, 225)", opacity=0.6), + line=attr(color="rgb(8, 48, 107)", width=1.5)) + + layout = Layout(;title="January 2013 Sales Report") + + plot(data, layout) +end +bar4() +``` + +```@example bar +function bar5() + x_value = ["Product A", "Product B", "Product C"] + y_value = [20, 14, 23] + + data = bar(;x=x_value, + y=y_value, + text=["$(i)% market share" for i in rand(15:30, 3)], + marker=attr(color="rgb(158, 202, 225)", opacity=0.6, + line=attr(color="rgb(8, 48, 107)", width=1.5))) + + annotations = [] + + for i in 1:length(x_value) + result = attr(x=x_value[i], + y=y_value[i], + text=y_value[i], + xanchor="center", + yanchor="bottom", + showarrow=false) + push!(annotations, result) + end + + layout = Layout(;title="January 2013 Sales Report", + annotations=annotations) + plot(data, layout) +end +bar5() +``` + +```@example bar +function bar6() + trace1 = bar(;x=["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec"], + y=[20, 14, 25, 16, 18, 22, 19, 15, 12, 16, 14, 17], + name="Primary Product", + marker_color="rgb(49, 130, 189)", + opacity=0.7) + trace2 = bar(;x=["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec"], + y=[19, 14, 22, 14, 16, 19, 15, 14, 10, 12, 12, 16], + name="Secondary Product", + marker=attr(color="rgb(204, 204, 204)", opacity=0.5)) + data = [trace1, trace2] + layout = Layout(;title="2013 Sales Report", + xaxis_tickangle=-45, + barmode="group") + plot(data, layout) +end +bar6() +``` + +```@example bar +function bar7() + data = bar(;x=["Feature $(s)" for s in 'A':'E'], + y=[20, 14, 23, 25, 22], + marker_color=["rgba(204, 204, 204, 1)", + "rgba(222, 45, 38, 0.8)", + "rgba(204, 204, 204, 1)", + "rgba(204, 204, 204, 1)", + "rgba(204, 204, 204, 1)"]) + layout = Layout(;title="Least Used Feature") + plot(data, layout) +end +bar7() +``` + +```@example bar +function bar8() + data = bar(;x=["Liam", "Sophie", "Jacob", "Mia", "William", "Olivia"], + y=[8.0, 8.0, 12.0, 12.0, 13.0, 20.0], + text=["4.17 below the mean", "4.17 below the mean", + "0.17 below the mean", "0.17 below the mean", + "0.83 above the mean", "7.83 above the mean"], + marker_color="rgb(142, 124, 195)") + layout = Layout(;title="Number of Graphs Made this Week", + font_family="Raleway, sans-serif", + showlegend=false, + xaxis_tickangle=-45, + yaxis=attr(zeroline=false, gridwidth=2), + bargap=0.05) + plot(data, layout) +end +bar8() +``` + +```@example bar +function bar9() + trace1 = bar(;x=1995:2012, + y=[219, 146, 112, 127, 124, 180, 236, 207, 236, 263, 350, + 430, 474, 526, 488, 537, 500, 439], + name="Rest of world", + marker_color="rgb(55, 83, 109)") + trace2 = bar(;x=1995:2012, + y=[16, 13, 10, 11, 28, 37, 43, 55, 56, 88, 105, 156, 270, + 299, 340, 403, 549, 499], + name="China", + marker_color="rgb(26, 118, 255)") + + data = [trace1, trace2] + + layout = Layout(;title="US Export of Plastic Scrap", + xaxis=attr(tickfont_size= 14, + tickfont_color="rgb(107, 107, 107)"), + yaxis=attr(title="USD (millions)", + titlefont=attr(size=16, + color="rgb(107, 107, 107)"), + tickfont=attr(size=14, + color="rgb(107, 107, 107)")), + legend=attr(x=0, y=1.0, bgcolor="rgba(255, 255, 255, 0)", + bordercolor="rgba(255, 255, 255, 0)"), + barmode="group", + bargap=0.15, + bargroupgap=0.1) + plot(data, layout) +end +bar9() +``` + +```@example bar +function bar10() + x_data = ["Product Revenue", "Services Revenue", "Total Revenue", + "Fixed Costs", "Variable Costs", "Total Costs", "Total"] + y_data = [400, 660, 660, 590, 400, 400, 340] + textList = ["\$430K", "\$260K", "\$690K", "\$-120K", "\$-200K", "\$-320K", + "\$370K"] + + #Base + trace1 = bar(;x=x_data, + y=[0, 430, 0, 570, 370, 370, 0], + marker_color="rgba(1, 1, 1, 0.0)") + + #Revenue + trace2 = bar(;x=x_data, + y=[430, 260, 690, 0, 0, 0, 0], + marker_color="rgba(55, 128, 191, 0.7)", + line=attr(color="rgba(55, 128, 191, 1.0)", width=2)) + + #Cost + trace3 = bar(;x=x_data, + y=[0, 0, 0, 120, 200, 320, 0], + marker=attr(color="rgba(219, 64, 82, 0.7)", + line=attr(color="rgba(219, 64, 82, 1.0)", width=2))) + + #Profit + trace4 = bar(;x=x_data, + y=[0, 0, 0, 0, 0, 0, 370], + marker=attr(color="rgba(50, 171, 96, 0.7)", + line=attr(color="rgba(50, 171, 96, 1.0)", width=2))) + + data = [trace1, trace2, trace3, trace4] + + annotations = [] + for i in 1:7 + result = attr(x=x_data[i], + y=y_data[i], + text=textList[i], + font=attr(;family="Arial", font_size=14, + font_color="rgba(245, 246, 249, 1)"), + showarrow=false) + push!(annotations, result) + end + + layout = Layout(;title="Annual Profit 2015", + barmode="stack", + paper_bgcolor="rgba(245, 246, 249, 1)", + plot_bgcolor="rgba(245, 246, 249, 1)", + width=600, + height=600, + showlegend=false, + xaxis_showtickabels=true, + annotations=annotations) + + plot(data, layout) +end +bar10() +``` + +```@example bar +function bar11() + trace1 = bar(;x=[1, 2, 3, 4], + y=[1, 4, 9, 16], + name="Trace1") + trace2 = bar(;x=[1, 2, 3, 4], + y=[6, -8, -4.5, 8], + name="Trace2") + trace3 = bar(;x=[1, 2, 3, 4], + y=[-15, -3, 4.5, -8], + name="Trace3") + trace4 = bar(;x=[1, 2, 3, 4], + y=[-1, 3, -3, -4], + name="Trace4") + data = [trace1, trace2, trace3, trace4] + layout = Layout(;xaxis_title="X axis", + yaxis_title="Y axis", + barmode="relative", + title="Relative Barmode") + plot(data, layout) +end +bar11() +``` + diff --git a/PlotlyJS/docs/src/examples/box_plots.md b/PlotlyJS/docs/src/examples/box_plots.md new file mode 100644 index 0000000..207e15b --- /dev/null +++ b/PlotlyJS/docs/src/examples/box_plots.md @@ -0,0 +1,251 @@ +# Box Plots + +```@example box_plots +using PlotlyJS +``` + +```@example box_plots +function box1() + y0 = rand(50) + y1 = rand(50) .+ 1 + trace1 = box(;y=y0) + trace2 = box(;y=y1) + data = [trace1, trace2] + plot(data) +end +box1() +``` + +```@example box_plots +function box2() + data = box(;y=[0, 1, 1, 2, 3, 5, 8, 13, 21], + boxpoints="all", + jitter=0.3, + pointpos=-1.8) + plot(data) +end +box2() +``` + +```@example box_plots +function box3() + trace1 = box(;x=[1, 2, 3, 4, 4, 4, 8, 9, 10], + name="Set 1") + trace2 = box(;x=[2, 3, 3, 3, 3, 5, 6, 6, 7], + name="Set 2") + data = [trace1, trace2] + layout = Layout(;title="Horizontal Box Plot") + + plot(data, layout) +end +box3() +``` + +```@example box_plots +function box4() + x0 = ["day 1", "day 1", "day 1", "day 1", "day 1", "day 1", + "day 2", "day 2", "day 2", "day 2", "day 2", "day 2"] + trace1 = box(;y=[0.2, 0.2, 0.6, 1.0, 0.5, 0.4, 0.2, 0.7, 0.9, 0.1, 0.5, 0.3], + x=x0, + name="kale", + marker_color="#3D9970") + trace2 = box(;y=[0.6, 0.7, 0.3, 0.6, 0.0, 0.5, 0.7, 0.9, 0.5, 0.8, 0.7, 0.2], + x=x0, + name="radishes", + marker_color="#FF4136") + trace3 = box(;y=[0.1, 0.3, 0.1, 0.9, 0.6, 0.6, 0.9, 1.0, 0.3, 0.6, 0.8, 0.5], + x=x0, + name="carrots", + marker_color="#FF851B") + data = [trace1, trace2, trace3] + layout = Layout(;yaxis=attr(title="normalized moisture", zeroline=false), + boxmode="group") + plot(data, layout) +end +box4() +``` + +```@example box_plots +function box5() + trace1 = box(;y=[0.75, 5.25, 5.5, 6, 6.2, 6.6, 6.80, 7.0, 7.2, 7.5, 7.5, + 7.75, 8.15, 8.15, 8.65, 8.93, 9.2, 9.5, 10, 10.25, 11.5, + 12, 16, 20.90, 22.3, 23.25], + name="All Points", + jitter=0.3, + pointpos=-1.8, + marker_color="rgb(7, 40, 89)", + boxpoints="all") + trace2 = box(;y=[0.75, 5.25, 5.5, 6, 6.2, 6.6, 6.80, 7.0, 7.2, 7.5, 7.5, + 7.75, 8.15, 8.15, 8.65, 8.93, 9.2, 9.5, 10, 10.25, 11.5, + 12, 16, 20.90, 22.3, 23.25], + name="Only Wiskers", + marker_color="rgb(9, 56, 125)", + boxpoints=false) + trace3 = box(;y=[0.75, 5.25, 5.5, 6, 6.2, 6.6, 6.80, 7.0, 7.2, 7.5, 7.5, + 7.75, 8.15, 8.15, 8.65, 8.93, 9.2, 9.5, 10, 10.25, 11.5, + 12, 16, 20.90, 22.3, 23.25], + name="Suspected Outlier", + marker=attr(color="rgb(8, 8, 156)", + outliercolor="rgba(219, 64, 82, 0.6)", + line=attr(outliercolor="rgba(219, 64, 82, 1.0)", + outlierwidth=2)), + boxpoints="suspectedoutliers") + trace4 = box(;y=[0.75, 5.25, 5.5, 6, 6.2, 6.6, 6.80, 7.0, 7.2, 7.5, 7.5, + 7.75, 8.15, 8.15, 8.65, 8.93, 9.2, 9.5, 10, 10.25, 11.5, + 12, 16, 20.90, 22.3, 23.25], + name="Wiskers and Outliers", + marker_color="rgb(107, 174, 214)", + boxpoints="Outliers") + data = [trace1, trace2, trace3, trace4] + layout = Layout(;title="Box Plot Styling Outliers") + plot(data, layout) +end +box5() +``` + +```@example box_plots +function box6() + trace1 = box(;y=[2.37, 2.16, 4.82, 1.73, 1.04, 0.23, 1.32, 2.91, 0.11, + 4.51, 0.51, 3.75, 1.35, 2.98, 4.50, 0.18, 4.66, 1.30, + 2.06, 1.19], + name="Only Mean", + marker_color="rgb(8, 81, 156)", + boxmean=true) + trace2 = box(;y=[2.37, 2.16, 4.82, 1.73, 1.04, 0.23, 1.32, 2.91, 0.11, + 4.51, 0.51, 3.75, 1.35, 2.98, 4.50, 0.18, 4.66, 1.30, + 2.06, 1.19], + name="Mean and Standard Deviation", + marker_color="rgb(10, 140, 208)", + boxmean="sd") + data = [trace1, trace2] + layout = Layout(;title="Box Plot Styling Mean and Standard Deviation") + plot(data, layout) +end +box6() +``` + +```@example box_plots +function box7() + y0 = ["day 1", "day 1", "day 1", "day 1", "day 1", "day 1", + "day 2", "day 2", "day 2", "day 2", "day 2", "day 2"] + trace1 = box(;x=[0.2, 0.2, 0.6, 1.0, 0.5, 0.4, 0.2, 0.7, 0.9, 0.1, 0.5, 0.3], + y=y0, + name="kale", + marker_color="#3D9970", + boxmean=false, + orientation="h") + trace2 = box(;x=[0.6, 0.7, 0.3, 0.6, 0.0, 0.5, 0.7, 0.9, 0.5, 0.8, 0.7, 0.2], + y=y0, + name="radishes", + marker_color="#FF4136", + boxmean=false, + orientation="h") + trace3 = box(;x=[0.1, 0.3, 0.1, 0.9, 0.6, 0.6, 0.9, 1.0, 0.3, 0.6, 0.8, 0.5], + y=y0, + name="carrots", + marker_color="#FF851B", + boxmean=false, + orientation="h") + data = [trace1, trace2, trace3] + layout = Layout(;title="Grouped Horizontal Box Plot", + xaxis=attr(title="normalized moisture", zeroline=false), + boxmode="group") + plot(data, layout) +end +box7() +``` + +```@example box_plots +function box8() + trace1 = box(;y=[1, 2, 3, 4, 4, 4, 8, 9, 10], + name="Sample A", + marker_color="rgb(214, 12, 140)") + trace2 = box(;y=[2, 3, 3, 3, 3, 5, 6, 6, 7], + name="Sample B", + marker_color="rgb(0, 128, 128)") + data = [trace1, trace2] + layout = Layout(;title="Colored Box Plot") + plot(data, layout) +end +box8() +``` + +```@example box_plots +function box9() + xData = ["Carmelo
Anthony", "Dwyane
Wade", "Deron
Williams", + "Brook
Lopez", "Damian
Lillard", "David
West", + "Blake
Griffin", "David
Lee", "Demar
Derozan"] + + _getrandom(num, mul) = mul .* rand(num) + + yData = Array[ + _getrandom(30, 10), + _getrandom(30, 20), + _getrandom(30, 25), + _getrandom(30, 40), + _getrandom(30, 45), + _getrandom(30, 30), + _getrandom(30, 20), + _getrandom(30, 15), + _getrandom(30, 43) + ] + colors = ["rgba(93, 164, 214, 0.5)", "rgba(255, 144, 14, 0.5)", + "rgba(44, 160, 101, 0.5)", "rgba(255, 65, 54, 0.5)", + "rgba(207, 114, 255, 0.5)", "rgba(127, 96, 0, 0.5)", + "rgba(255, 140, 184, 0.5)", "rgba(79, 90, 117, 0.5)", + "rgba(222, 223, 0, 0.5)"] + + data = GenericTrace[] + for i in 1:length(xData) + trace = box(;y=yData[i], + name=xData[i], + boxpoints="all", + jitter=0.5, + whiskerwidth=0.2, + fillcolor="cls", + marker_size=2, + line_width=1) + push!(data, trace) + end + + t = "Points Scored by the Top 9 Scoring NBA Players in 2012" + layout = Layout(;title=t, + yaxis=attr(autorange=true, showgrid=true, zeroline=true, + dtick=5, gridcolor="rgb(255, 255, 255)", + gridwidth=1, + zerolinecolor="rgb(255, 255, 255)", + zerolinewidth=2), + margin=attr(l=40, r=30, b=80, t=100), + paper_bgcolor="rgb(243, 243, 243)", + plot_bgcolor="rgb(243, 243, 243)", + showlegend=false) + plot(data, layout) +end +box9() +``` + +```@example box_plots +function box10() + n_box = 30 + colors = ["hsl($i, 50%, 50%)" for i in range(0, stop=360, length=n_box)] + + gen_y_data(i) = + (3.5*sin(pi*i/n_box) + i/n_box) .+ (1.5+0.5*cos(pi*i/n_box)).*rand(10) + + ys = Array[gen_y_data(i) for i in 1:n_box] + + # Create Traces + data = GenericTrace[box(y=y, marker_color=mc) for (y, mc) in zip(ys, colors)] + + #Format the layout + layout = Layout(;xaxis=attr(;showgrid=false, zeroline=false, + tickangle=60, showticklabels=true), + yaxis=attr(;zeroline=false, gridcolor="white"), + paper_bgcolor="rgb(233, 233, 233)", + plot_bgcolor="rgb(233, 233, 233)", + showlegend=true) + plot(data, layout) +end +box10() +``` + diff --git a/PlotlyJS/docs/src/examples/contour.md b/PlotlyJS/docs/src/examples/contour.md new file mode 100644 index 0000000..3450479 --- /dev/null +++ b/PlotlyJS/docs/src/examples/contour.md @@ -0,0 +1,254 @@ +# Contour + +```@example contour +using PlotlyJS +``` + +```@example contour +function contour1() + x = y = [-2*pi + 4*pi*i/100 for i in 1:100] + z = [sin(x[i]) * cos(y[j]) * sin(x[i]*x[i]+y[j]*y[j])/log(x[i]*x[i]+y[j]*y[j]+1) + for i in 1:100 for j in 1:100] + z_ = [z[i:i+99] for i in 1:100:10000] + + data = contour(;z=z_, x=x, y=y) + + plot(data) +end +contour1() +``` + +```@example contour +function contour2() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z) + + layout = Layout(;title="Basic Contour Plot") + plot(data, layout) +end +contour2() +``` + +```@example contour +function contour3() + x = [-9, -6, -5 , -3, -1] + y = [0, 1, 4, 5, 7] + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + trace = contour(x=x, y=y, z=z) + + layout = Layout(title="Setting the X and Y Coordinates in a Contour Plot") + plot(trace, layout) +end +contour3() +``` + +```@example contour +function contour4() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, colorscale="Jet") + + layout = Layout(;title="Colorscale for Contour Plot") + plot(data, layout) +end +contour4() +``` + +```@example contour +function contour5() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, + colorscale="Jet", + autocontour=false, + contours=Dict(:start=>0, :end=>8, :size=>2)) + + layout = Layout(;title="Customizing Size and Range of Contours") + plot(data, layout) +end +contour5() +``` + +```@example contour +function contour6() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, colorscale="Jet", dx=10, x0=5, dy=10, y0=10) + + layout = Layout(;title="Customizing Spacing Between X and Y Axis Ticks") + + plot(data, layout) +end +contour6() +``` + +```@example contour +function contour7() + z = [NaN NaN NaN 12 13 14 15 16 + NaN 1 NaN 11 NaN NaN NaN 17 + NaN 2 6 7 NaN NaN NaN 18 + NaN 3 NaN 8 NaN NaN NaN 19 + 5 4 10 9 NaN NaN NaN 20 + NaN NaN NaN 27 NaN NaN NaN 21 + NaN NaN NaN 26 25 24 23 22]' + + p1 = plot(contour(;z=z, showscale=false)) + p2 = plot(contour(;z=z, connectgaps=true, showscale=false)) + p3 = plot(heatmap(;z=z, zsmooth="best",showscale=false)) + p4 = plot(heatmap(;z=z, zsmooth="best", connectgaps=true, showscale=false)) + + p = [p1 p2; p3 p4] + + relayout!(p, title="Connect the Gaps Between Null Values in the Z Matrix") + + p +end +contour7() +``` + +```@example contour +function contour8() + z = [2 4 7 12 13 14 15 16 + 3 1 6 11 12 13 16 17 + 4 2 7 7 11 14 17 18 + 5 3 8 8 13 15 18 19 + 7 4 10 9 16 18 20 19 + 9 10 5 27 23 21 21 21 + 11 14 17 26 25 24 23 22] + + p1 = plot(contour(;z=z, line_smoothing=0)) + p2 = plot(contour(;z=z, line_smoothing=0.85)) + + p = [p1 p2] + + relayout!(p, title="Smoothing Contour Lines") + + p +end +contour8() +``` + +```@example contour +function contour9() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, contours_coloring="heatmap") + + layout = Layout(;title="Smooth Contour Coloring") + plot(data, layout) +end +contour9() +``` + +```@example contour +function contour10() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, colorscale="Jet", contours_coloring="lines") + + layout = Layout(;title="Contour Lines") + plot(data, layout) +end +contour10() +``` + +```@example contour +function contour11() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, + colorscale=[[0, "rgb(166,206,227)"], + [0.25, "rgb(31,120,180)"], + [0.45, "rgb(178,223,138)"], + [0.64, "rgb(51,160,44)"], + [0.85, "rgb(251,154,153)"], + [1, "rgb(227,26,28)"]]) + + layout = Layout(;title="Custom Contour Plot Colorscale") + + plot(data, layout) +end +contour11() +``` + +```@example contour +function contour12() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, + colorbar=attr(;title="Color Bar Title",titleside="right", + titlefont=attr(;size=14, + family="Arial, sans-serif"))) + + layout = Layout(;title="Colorbar with Title") + plot(data,layout) +end +contour12() +``` + +```@example contour +function contour13() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, + colorbar=attr(;thickness=75, thicknessmode="pixels", + len=0.9, lenmode="fraction", + outlinewidth=0)) + + layout = Layout(;title="Colorbar Size for Contour Plots") + plot(data,layout) +end +contour13() +``` + +```@example contour +function contour14() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, + colorbar=attr(;ticks="outside", dtick=1, + tickwidth=2, ticklen=10, + tickcolor="grey", showticklabels=true, + tickfont_size=15, xpad=50)) + + layout = Layout(;title="Styling Color Bar Ticks for Contour Plots") + plot(data,layout) +end +contour14() +``` + diff --git a/PlotlyJS/docs/src/examples/finance.md b/PlotlyJS/docs/src/examples/finance.md new file mode 100644 index 0000000..7a79ecf --- /dev/null +++ b/PlotlyJS/docs/src/examples/finance.md @@ -0,0 +1,60 @@ +# Finance + +```@example finance +using PlotlyJS, HTTP, CSV, DataFrames +``` + +```@example finance +function ohlc1() + t = ohlc(open=[33.0, 33.3, 33.5, 33.0, 34.1], + high=[33.1, 33.3, 33.6, 33.2, 34.8], + low=[32.7, 32.7, 32.8, 32.6, 32.8], + close=[33.0, 32.9, 33.3, 33.1, 33.1]) + plot(t) +end +ohlc1() +``` + +```@example finance +function ohlc2() + function get_ohlc(ticker; kwargs...) + res = HTTP.get("https://www.quandl.com/api/v3/datasets/WIKI/$(ticker)/data.csv?start_date=2017-01-01") + df = DataFrame(CSV.File(res.body)) + ohlc(df, x=:Date, open=:Open, high=:High, low=:Low, close=:Close; kwargs...) + end + + p1 = plot(get_ohlc("AAPL", name="Apple"), Layout(title="Apple")) + p2 = plot(get_ohlc("GOOG", name="Google"), Layout(title="Google")) + + [p1 p2] +end +ohlc2() +``` + +```@example finance +function candlestick1() + t = candlestick(open=[33.0, 33.3, 33.5, 33.0, 34.1], + high=[33.1, 33.3, 33.6, 33.2, 34.8], + low=[32.7, 32.7, 32.8, 32.6, 32.8], + close=[33.0, 32.9, 33.3, 33.1, 33.1]) + plot(t) +end +candlestick1() +``` + +```@example finance +function candlestick2() + function get_candlestick(ticker; kwargs...) + res = HTTP.get("https://www.quandl.com/api/v3/datasets/WIKI/$(ticker)/data.csv?start_date=2017-01-01") + df = DataFrame(CSV.File(res.body)) + candlestick(df, x=:Date, open=:Open, high=:High, low=:Low, close=:Close; kwargs...) + end + + p1 = plot(get_candlestick("AAPL", name="Apple"), Layout(title="Apple")) + p2 = plot(get_candlestick("GOOG", name="Google"), Layout(title="Google")) + + [p1 p2] +end +candlestick2() +``` + diff --git a/PlotlyJS/docs/src/examples/heatmaps.md b/PlotlyJS/docs/src/examples/heatmaps.md new file mode 100644 index 0000000..de7310c --- /dev/null +++ b/PlotlyJS/docs/src/examples/heatmaps.md @@ -0,0 +1,26 @@ +# Heatmaps + +```@example heatmaps +using PlotlyJS, Random +Random.seed!(42) +``` + +```@example heatmaps +function heatmap1() + plot(heatmap(z=[1 20 30; 20 1 60; 30 60 1])) +end +heatmap1() +``` + +```@example heatmaps +function heatmap2() + trace = heatmap( + x=["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"], + y=["Morning", "Afternoon", "Evening"], + z=rand(1:30, 5, 3) + ) + plot(trace) +end +heatmap2() +``` + diff --git a/PlotlyJS/docs/src/examples/histograms.md b/PlotlyJS/docs/src/examples/histograms.md new file mode 100644 index 0000000..b432591 --- /dev/null +++ b/PlotlyJS/docs/src/examples/histograms.md @@ -0,0 +1,20 @@ +# Histograms + +```@example histograms +using PlotlyJS +``` + +```@example histograms +function two_hists() + x0 = randn(500) + x1 = x0 .+ 1 + + trace1 = histogram(x=x0, opacity=0.75) + trace2 = histogram(x=x1, opacity=0.75) + data = [trace1, trace2] + layout = Layout(barmode="overlay") + plot(data, layout) +end +two_hists() +``` + diff --git a/PlotlyJS/docs/src/examples/line_scatter.md b/PlotlyJS/docs/src/examples/line_scatter.md new file mode 100644 index 0000000..40362c6 --- /dev/null +++ b/PlotlyJS/docs/src/examples/line_scatter.md @@ -0,0 +1,336 @@ +# Line Scatter + +```@example line_scatter +using PlotlyJS, DataFrames, CSV, Dates, HTTP +``` + +```@example line_scatter +function linescatter1() + trace1 = scatter(;x=1:4, y=[10, 15, 13, 17], mode="markers") + trace2 = scatter(;x=2:5, y=[16, 5, 11, 9], mode="lines") + trace3 = scatter(;x=1:4, y=[12, 9, 15, 12], mode="lines+markers") + plot([trace1, trace2, trace3]) +end +linescatter1() +``` + +```@example line_scatter +function linescatter2() + trace1 = scatter(;x=1:5, y=[1, 6, 3, 6, 1], + mode="markers", name="Team A", + text=["A-1", "A-2", "A-3", "A-4", "A-5"], + marker_size=12) + + trace2 = scatter(;x=1:5 + 0.5, y=[4, 1, 7, 1, 4], + mode="markers", name="Team B", + text=["B-a", "B-b", "B-c", "B-d", "B-e"]) + # setting marker.size this way is _equivalent_ to what we did for trace1 + trace2["marker"] = Dict(:size => 12) + + data = [trace1, trace2] + layout = Layout(;title="Data Labels Hover", xaxis_range=[0.75, 5.25], + yaxis_range=[0, 8]) + plot(data, layout) +end +linescatter2() +``` + +```@example line_scatter +function linescatter3() + trace1 = scatter(;x=1:5, y=[1, 6, 3, 6, 1], + mode="markers+text", name="Team A", + textposition="top center", + text=["A-1", "A-2", "A-3", "A-4", "A-5"], + marker_size=12, textfont_family="Raleway, sans-serif") + + trace2 = scatter(;x=1:5 + 0.5, y=[4, 1, 7, 1, 4], + mode="markers+text", name="Team B", + textposition="bottom center", + text=["B-a", "B-b", "B-c", "B-d", "B-e"], + marker_size=12, textfont_family="Times New Roman") + + data = [trace1, trace2] + + layout = Layout(;title="Data Labels on the Plot", xaxis_range=[0.75, 5.25], + yaxis_range=[0, 8], legend_y=0.5, legend_yref="paper", + legend=attr(family="Arial, sans-serif", size=20, + color="grey")) + plot(data, layout) +end +linescatter3() +``` + +```@example line_scatter +function linescatter4() + trace1 = scatter(;y=fill(5, 40), mode="markers", marker_size=40, + marker_color=0:39) + layout = Layout(title="Scatter Plot with a Color Dimension") + plot(trace1, layout) +end +linescatter4() +``` + +```@example line_scatter +function linescatter5() + + country = ["Switzerland (2011)", "Chile (2013)", "Japan (2014)", + "United States (2012)", "Slovenia (2014)", "Canada (2011)", + "Poland (2010)", "Estonia (2015)", "Luxembourg (2013)", + "Portugal (2011)"] + + votingPop = [40, 45.7, 52, 53.6, 54.1, 54.2, 54.5, 54.7, 55.1, 56.6] + regVoters = [49.1, 42, 52.7, 84.3, 51.7, 61.1, 55.3, 64.2, 91.1, 58.9] + + # notice use of `attr` function to make nested attributes + trace1 = scatter(;x=votingPop, y=country, mode="markers", + name="Percent of estimated voting age population", + marker=attr(color="rgba(156, 165, 196, 0.95)", + line_color="rgba(156, 165, 196, 1.0)", + line_width=1, size=16, symbol="circle")) + + trace2 = scatter(;x=regVoters, y=country, mode="markers", + name="Percent of estimated registered voters") + # also could have set the marker props above by using a dict + trace2["marker"] = Dict(:color => "rgba(204, 204, 204, 0.95)", + :line => Dict(:color => "rgba(217, 217, 217, 1.0)", + :width => 1), + :symbol => "circle", + :size => 16) + + data = [trace1, trace2] + layout = Layout(Dict{Symbol,Any}(:paper_bgcolor => "rgb(254, 247, 234)", + :plot_bgcolor => "rgb(254, 247, 234)"); + title="Votes cast for ten lowest voting age population in OECD countries", + width=600, height=600, hovermode="closest", + margin=Dict(:l => 140, :r => 40, :b => 50, :t => 80), + xaxis=attr(showgrid=false, showline=true, + linecolor="rgb(102, 102, 102)", + titlefont_color="rgb(204, 204, 204)", + tickfont_color="rgb(102, 102, 102)", + autotick=false, dtick=10, ticks="outside", + tickcolor="rgb(102, 102, 102)"), + legend=attr(font_size=10, yanchor="middle", + xanchor="right"), + ) + plot(data, layout) +end +linescatter5() +``` + +```@example line_scatter +function linescatter6() + trace1 = scatter(;x=[52698, 43117], y=[53, 31], + mode="markers", + name="North America", + text=["United States", "Canada"], + marker=attr(color="rgb(164, 194, 244)", size=12, + line=attr(color="white", width=0.5)) + ) + + trace2 = scatter(;x=[39317, 37236, 35650, 30066, 29570, 27159, 23557, 21046, 18007], + y=[33, 20, 13, 19, 27, 19, 49, 44, 38], + mode="markers", name="Europe", + marker_size=12, marker_color="rgb(255, 217, 102)", + text=["Germany", "Britain", "France", "Spain", "Italy", + "Czech Rep.", "Greece", "Poland", "Portugal"]) + + trace3 = scatter(;x=[42952, 37037, 33106, 17478, 9813, 5253, 4692, 3899], + y=[23, 42, 54, 89, 14, 99, 93, 70], + mode="markers", + name="Asia/Pacific", + marker_size=12, marker_color="rgb(234, 153, 153)", + text=["Australia", "Japan", "South Korea", "Malaysia", + "China", "Indonesia", "Philippines", "India"]) + + trace4 = scatter(;x=[19097, 18601, 15595, 13546, 12026, 7434, 5419], + y=[43, 47, 56, 80, 86, 93, 80], + mode="markers", name="Latin America", + marker_size=12, marker_color="rgb(142, 124, 195)", + text=["Chile", "Argentina", "Mexico", "Venezuela", + "Venezuela", "El Salvador", "Bolivia"]) + + data = [trace1, trace2, trace3, trace4] + + layout = Layout(;title="Quarter 1 Growth", + xaxis=attr(title="GDP per Capital", showgrid=false, zeroline=false), + yaxis=attr(title="Percent", zeroline=false)) + + plot(data, layout) +end +linescatter6() +``` + +```@example line_scatter +function batman() + # reference: https://github.com/alanedelman/18.337_2015/blob/master/Lecture01_0909/The%20Bat%20Curve.ipynb + σ(x) = @. √(1 - x.^2) + el(x) = @. 3 * σ(x / 7) + s(x) = @. 4.2 - 0.5 * x - 2.0 * σ(0.5 * x - 0.5) + b(x) = @. σ(abs(2 - x) - 1) - x.^2 / 11 + 0.5x - 3 + c(x) = [1.7, 1.7, 2.6, 0.9] + + p(i, f; kwargs...) = scatter(;x=[-i; 0.0; i], y=[f(i); NaN; f(i)], + marker_color="black", showlegend=false, + kwargs...) + traces = vcat(p(3:0.1:7, el; name="wings 1"), + p(4:0.1:7, t -> -el(t); name="wings 2"), + p(1:0.1:3, s; name="Shoulders"), + p(0:0.1:4, b; name="Bottom"), + p([0, 0.5, 0.8, 1], c; name="head")) + + plot(traces, Layout(title="Batman")) +end +batman() +``` + +```@example line_scatter +function dumbell() + # reference: https://plot.ly/r/dumbbell-plots/ + # read Data into dataframe + url = "https://raw.githubusercontent.com/plotly/datasets/master/school_earnings.csv" + df = DataFrame(CSV.File(HTTP.get(url).body)) + + # sort dataframe by male earnings + df = sort(df, :Men, rev=false) + + men = scatter(;y=df.School, x=df.Men, mode="markers", name="Men", + marker=attr(color="blue", size=12)) + women = scatter(;y=df.School, x=df.Women, mode="markers", name="Women", + marker=attr(color="pink", size=12)) + + lines = map(eachrow(df)) do r + scatter(y=fill(r.School, 2), x=[r.Women, r.Men], mode="lines", + name=r.School, showlegend=false, line_color="gray") + end + + data = Base.typed_vcat(GenericTrace, men, women, lines) + layout = Layout(width=650, height=650, margin_l=100, yaxis_title="School", + xaxis_title="Annual Salary (thousands)", + title="Gender earnings disparity") + + plot(data, layout) +end +dumbell() +``` + +```@example line_scatter +function errorbars1() + trace1 = scatter(;x=vcat(1:10, 10:-1:1), + y=vcat(2:11, 9:-1:0), + fill="tozerox", + fillcolor="rgba(0, 100, 80, 0.2)", + line_color="transparent", + name="Fair", + showlegend=false) + + trace2 = scatter(;x=vcat(1:10, 10:-1:1), + y=[5.5, 3.0, 5.5, 8.0, 6.0, 3.0, 8.0, 5.0, 6.0, 5.5, 4.75, + 5.0, 4.0, 7.0, 2.0, 4.0, 7.0, 4.4, 2.0, 4.5], + fill="tozerox", + fillcolor="rgba(0, 176, 246, 0.2)", + line_color="transparent", + name="Premium", + showlegend=false) + + trace3 = scatter(;x=vcat(1:10, 10:-1:1), + y=[11.0, 9.0, 7.0, 5.0, 3.0, 1.0, 3.0, 5.0, 3.0, 1.0, + -1.0, 1.0, 3.0, 1.0, -0.5, 1.0, 3.0, 5.0, 7.0, 9.], + fill="tozerox", + fillcolor="rgba(231, 107, 243, 0.2)", + line_color="transparent", + name="Fair", + showlegend=false) + + trace4 = scatter(;x=1:10, y=1:10, + line_color="rgb(00, 100, 80)", + mode="lines", + name="Fair") + + trace5 = scatter(;x=1:10, + y=[5.0, 2.5, 5.0, 7.5, 5.0, 2.5, 7.5, 4.5, 5.5, 5.], + line_color="rgb(0, 176, 246)", + mode="lines", + name="Premium") + + trace6 = scatter(;x=1:10, y=vcat(10:-2:0, [2, 4,2, 0]), + line_color="rgb(231, 107, 243)", + mode="lines", + name="Ideal") + data = [trace1, trace2, trace3, trace4, trace5, trace6] + layout = Layout(;paper_bgcolor="rgb(255, 255, 255)", + plot_bgcolor="rgb(229, 229, 229)", + + xaxis=attr(gridcolor="rgb(255, 255, 255)", + range=[1, 10], + showgrid=true, + showline=false, + showticklabels=true, + tickcolor="rgb(127, 127, 127)", + ticks="outside", + zeroline=false), + + yaxis=attr(gridcolor="rgb(255, 255, 255)", + showgrid=true, + showline=false, + showticklabels=true, + tickcolor="rgb(127, 127, 127)", + ticks="outside", + zeroline=false)) + + plot(data, layout) +end +errorbars1() +``` + +```@example line_scatter +function errorbars2() + function random_dates(d1::DateTime, d2::DateTime, n::Int) + map(Date, sort!(rand(d1:Dates.Hour(12):d2, n))) + end + + function _random_number(num, mul) + value = [] + j = 0 + rand = 0 + while j <= num + 1 + rand = rand() * mul + append!(value, [rand]) + j += 1 + end + return value + end + + dates = random_dates(DateTime(2001, 1, 1), DateTime(2005, 12, 31), 50) + + trace1 = scatter(;x=dates, + y=20.0 .* rand(50), + line_width=0, + marker_color="444", + mode="lines", + name="Lower Bound") + + trace2 = scatter(;x=dates, + y=21.0 .* rand(50), + fill="tonexty", + fillcolor="rgba(68, 68, 68, 0.3)", + line_color="rgb(31, 119, 180)", + mode="lines", + name="Measurement") + + trace3 = scatter(;x=dates, + y=22.0 .* rand(50), + fill="tonexty", + fillcolor="rgba(68, 68, 68, 0.3)", + line_width=0, + marker_color="444", + mode="lines", + name="Upper Bound") + + data = [trace1, trace2, trace3] + t = "Continuous, variable value error bars
Notice the hover text!" + layout = Layout(;title=t, yaxis_title="Wind speed (m/s)") + plot(data, layout) +end +errorbars2() +``` + diff --git a/PlotlyJS/docs/src/examples/maps.md b/PlotlyJS/docs/src/examples/maps.md new file mode 100644 index 0000000..e6ffb3e --- /dev/null +++ b/PlotlyJS/docs/src/examples/maps.md @@ -0,0 +1,54 @@ +# Maps + +```@example maps +using PlotlyJS, DataFrames, CSV, HTTP +``` + +```@example maps +function maps1() + marker = attr(size=[20, 30, 15, 10], + color=[10, 20, 40, 50], + cmin=0, + cmax=50, + colorscale="Greens", + colorbar=attr(title="Some rate", + ticksuffix="%", + showticksuffix="last"), + line_color="black") + trace = scattergeo(;mode="markers", locations=["FRA", "DEU", "RUS", "ESP"], + marker=marker, name="Europe Data") + layout = Layout(geo_scope="europe", geo_resolution=50, width=500, height=550, + margin=attr(l=0, r=0, t=10, b=0)) + plot(trace, layout) +end +maps1() +``` + +```@example maps +function maps2() + # read Data into dataframe + url = "https://raw.githubusercontent.com/plotly/datasets/master/2014_us_cities.csv" + df = DataFrame(CSV.File(HTTP.get(url).body)) + + trace = scattergeo(;locationmode="USA-states", + lat=df.lat, + lon=df.lon, + hoverinfo="text", + text=[string(x.name, " pop: ", x.pop) for x in eachrow(df)], + marker_size=df.pop ./ 50_000, + marker_line_color="black", marker_line_width=2) + geo = attr(scope="usa", + projection_type="albers usa", + showland=true, + landcolor="rgb(217, 217, 217)", + subunitwidth=1, + countrywidth=1, + subunitcolor="rgb(255,255,255)", + countrycolor="rgb(255,255,255)") + + layout = Layout(;title="2014 US City Populations", showlegend=false, geo=geo) + plot(trace, layout) +end +maps2() +``` + diff --git a/PlotlyJS/docs/src/examples/shapes.md b/PlotlyJS/docs/src/examples/shapes.md new file mode 100644 index 0000000..a1cf975 --- /dev/null +++ b/PlotlyJS/docs/src/examples/shapes.md @@ -0,0 +1,182 @@ +# Shapes + +```@example shapes +using PlotlyJS, Distributions +``` + +```@example shapes +function house() + trace1 = scatter() + x0 = [2, 2, 5.5, 9, 9, 2, 5, 5, 6] + y0 = [1, 5.5, 9.5, 5.5, 1, 5.5, 1, 4, 4] + x1 = [2, 5.5, 9, 9, 2, 9, 5, 6, 6] + y1 = [5.5, 9.5, 5.5, 1, 1, 5.5, 4, 4, 1] + shapes = line(x0, x1, y0, y1; xref="x", yref="y") + plot([trace1], + Layout(;shapes=shapes, xaxis_range=(1, 10), yaxis_range=(0, 10))) +end +house() +``` + +```@example shapes +function house2() + trace1 = scatter() + _p = string("M 2 1 L 2 5.5 L 5.5 9.6 L 9 5.5 L 9 1 L 2 1 ", + "M 2 5.5 L 9 5.5 ", + "M 5 1 L 5 4 L 6 4 L 6 1 Z") + plot([trace1], + Layout(;shapes=[path(_p)], xaxis_range=(1, 10), yaxis_range=(0, 10))) +end +house2() +``` + +```@example shapes +function clusters() + x0 = rand(Normal(2, 0.45), 300) + y0 = rand(Normal(2, 0.45), 300) + x1 = rand(Normal(6, 0.4), 200) + y1 = rand(Normal(6, 0.4), 200) + x2 = rand(Normal(4, 0.3), 200) + y2 = rand(Normal(4, 0.3), 200) + + data = [scatter(;x=x0, y=y0, mode="markers"), + scatter(;x=x1, y=y1, mode="markers"), + scatter(;x=x2, y=y2, mode="markers"), + scatter(;x=x1, y=y0, mode="markers")] + + args = [(x0, y0, "blue"), (x1, y1, "orange"), (x2, y2, "green"), + (x1, y0, "red")] + shapes = [circle(x0=minimum(x), y0=minimum(y), + x1=maximum(x), y1=maximum(y); + opacity=0.2, fillcolor=c, line_color=c) + for (x, y, c) in args] + plot(data, Layout(;height=400, width=480, showlegend=false, shapes=shapes)) +end +clusters() +``` + +```@example shapes +function temperature() + x = ["2015-02-01", "2015-02-02", "2015-02-03", "2015-02-04", "2015-02-05", + "2015-02-06", "2015-02-07", "2015-02-08", "2015-02-09", "2015-02-10", + "2015-02-11", "2015-02-12", "2015-02-13", "2015-02-14", "2015-02-15", + "2015-02-16", "2015-02-17", "2015-02-18", "2015-02-19", "2015-02-20", + "2015-02-21", "2015-02-22", "2015-02-23", "2015-02-24", "2015-02-25", + "2015-02-26", "2015-02-27", "2015-02-28"] + y = rand(1:20, length(x)) + data = scatter(;x=x, y=y, name="temperature", mode="line") + + shapes = rect(["2015-02-04", "2015-02-20"], ["2015-02-06", "2015-02-22"], + 0, 1; fillcolor="#d3d3d3", opacity=0.2, line_width=0, + xref="x", yref="paper") + plot(data, Layout(shapes=shapes, width=500, height=500)) +end +temperature() +``` + +```@example shapes +function vlines1() + # one scalar argument produces one line. Need to wrap in an array because + # layout.shapes should be an array + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = [vline(2)] + plot([trace1], Layout(;shapes=shapes)) +end +vlines1() +``` + +```@example shapes +function vlines2() + # one argument draws a vertical line up the entire plot + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = vline([2, 6]) + plot([trace1], Layout(;shapes=shapes)) +end +vlines2() +``` + +```@example shapes +function vlines3() + # yref paper makes the 2nd and 3rd arguments on a (0, 1) scale vertically + # so 0.5 is 1/2 through the plot regardless of the values on y-axis + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = vline([2, 6], 0, 0.5; yref="paper") + plot([trace1], Layout(;shapes=shapes)) +end +vlines3() +``` + +```@example shapes +function vlines4() + # Whichever argument is a scalar is repeated + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = vline([2, 6], 0, [0.5, 0.75]; yref="paper") + plot([trace1], Layout(;shapes=shapes)) +end +vlines4() +``` + +```@example shapes +function vlines5() + # we can also set arbitrary line attributes line color and dash + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = vline([2, 6], 0, [0.5, 0.75]; yref="paper", + line_color="green", line_dash="dashdot") + plot([trace1], Layout(;shapes=shapes)) +end +vlines5() +``` + +```@example shapes +function hlines1() + # one scalar argument produces one line. Need to wrap in an array because + # layout.shapes should be an array + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = [hline(2)] + plot([trace1], Layout(;shapes=shapes)) +end +hlines1() +``` + +```@example shapes +function hlines2() + # one argument draws a horizontal line across the entire plot + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = hline([25, 81]) + plot([trace1], Layout(;shapes=shapes)) +end +hlines2() +``` + +```@example shapes +function hlines3() + # xref paper makes the 2nd and 3rd arguments on a (0, 1) scale horizontally + # so 0.5 is 1/2 through the plot regardless of the values on x-axis + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = hline([25, 81], 0, 0.5; xref="paper") + plot([trace1], Layout(;shapes=shapes)) +end +hlines3() +``` + +```@example shapes +function hlines4() + # Whichever argument is a scalar is repeated + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = hline([25, 81], 0, [0.5, 0.75]; xref="paper") + plot([trace1], Layout(;shapes=shapes)) +end +hlines4() +``` + +```@example shapes +function hlines5() + # we can also set arbitrary line attributes line color and dash + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = hline([25, 81], 0, [0.5, 0.75]; xref="paper", + line_color="green", line_dash="dashdot") + plot([trace1], Layout(;shapes=shapes)) +end +hlines5() +``` + diff --git a/PlotlyJS/docs/src/examples/subplots.md b/PlotlyJS/docs/src/examples/subplots.md new file mode 100644 index 0000000..094a7e4 --- /dev/null +++ b/PlotlyJS/docs/src/examples/subplots.md @@ -0,0 +1,168 @@ +# Subplots + +```@example subplots +using PlotlyJS, Dates +include("../../../examples/line_scatter.jl") +``` + +```@example subplots +function subplots1() + p1 = linescatter1() + p2 = linescatter2() + p = [p1 p2] + p +end +subplots1() +``` + +```@example subplots +function subplots2() + p1 = linescatter1() + p2 = linescatter2() + p = [p1; p2] + p +end +subplots2() +``` + +```@example subplots +function subplots3() + p1 = linescatter6() + p2 = linescatter2() + p3 = linescatter3() + p4 = batman() + p = [p1 p2; p3 p4] + p.plot.layout["showlegend"] = false + p.plot.layout["width"] = 1000 + p.plot.layout["height"] = 600 + p +end +subplots3() +``` + +```@example subplots +function subplots_withcomprehension() + hcat([plot(scatter(x=1:5, y=rand(5))) for i in 1:3]...) +end +subplots_withcomprehension() +``` + +```@example subplots +function subplots_withsharedaxes() + data = [ + scatter(x=1:3, y=2:4), + scatter(x=20:10:40, y=fill(5, 3), xaxis="x2", yaxis="y"), + scatter(x=2:4, y=600:100:800, xaxis="x", yaxis="y3"), + scatter(x=4000:1000:6000, y=7000:1000:9000, xaxis="x4", yaxis="y4") + ] + layout = Layout( + xaxis_domain=[0, 0.45], + yaxis_domain=[0, 0.45], + xaxis4=attr(domain=[0.55, 1.0], anchor="y4"), + xaxis2_domain=[0.55, 1], + yaxis3_domain=[0.55, 1], + yaxis4=attr(domain=[0.55, 1], anchor="x4") + ) + plot(data, layout) +end +subplots_withsharedaxes() +``` + +```@example subplots +function with_make_subplots1() + + # The `shared_xaxes` argument to `make_subplots` can be used to link the x + # axes of subplots in the resulting figure. The `vertical_spacing` argument + # is used to control the vertical spacing between rows in the subplot grid. + + # Here is an example that creates a figure with 3 vertically stacked + # subplots with linked x axes. A small vertical spacing value is used to + # reduce the spacing between subplot rows. + + p = make_subplots(rows=3, cols=1, shared_xaxes=true, vertical_spacing=0.02) + add_trace!(p, scatter(x=0:2, y=10:12), row=3, col=1) + add_trace!(p, scatter(x=2:4, y=100:10:120), row=2, col=1) + add_trace!(p, scatter(x=3:5, y=1000:100:1200), row=1, col=1) + relayout!(p, title_text="Stacked Subplots with Shared X-Axes") + p +end +with_make_subplots1() +``` + +```@example subplots +function with_make_subplots2() + # The `shared_yaxes` argument to `make_subplots` can be used to link the y + # axes of subplots in the resulting figure. + + # Here is an example that creates a figure with a 2 x 2 subplot grid, where + # the y axes of each row are linked. + + p = make_subplots(rows=3, cols=2, shared_yaxes=true) + add_trace!(p, scatter(x=0:2, y=10:12), row=1, col=1) + add_trace!(p, scatter(x=20:10:40, y=1:3), row=1, col=2) + add_trace!(p, scatter(x=3:5, y=600:100:800), row=2, col=1) + add_trace!(p, scatter(x=3:5, y=1000:100:1200), row=2, col=2) + relayout!(p, title_text="Multiple Subplots with Shared Y-Axes") + p +end +with_make_subplots2() +``` + +```@example subplots +function with_make_subplots3() + # The `specs` argument to `make_subplots` is used to configure per-subplot + # options. `specs` must be a `Matrix` with dimensions that match those + # provided as the `rows` and `cols` arguments. The elements of `specs` may + # either be `missing`, indicating no subplot should be initialized starting + # with this grid cell, or an instance of `Spec` containing subplot options. + # The `colspan` subplot option specifies the number of grid columns that the + # subplot starting in the given cell should occupy. If unspecified, + # `colspan` defaults to 1. + + # Here is an example that creates a 2 by 2 subplot grid containing 3 + # subplots. The subplot `specs` element for position (2, 1) has a `colspan` + # value of 2, causing it to span the full figure width. The subplot `specs` + # element f or position (2, 2) is `None` because no subplot begins at this + # location in the grid. + p = make_subplots( + rows=2, cols=2, + specs=[Spec() Spec(); Spec(colspan=2) missing], + subplot_titles=["First Subplot" "Second Subplot"; "Third Subplot" missing] + ) + + add_trace!(p, scatter(x=[1, 2], y=[1, 2]), row=1, col=1) + add_trace!(p, scatter(x=[1, 2], y=[1, 2]), row=1, col=2) + add_trace!(p, scatter(x=[1, 2, 3], y=[2, 1, 2]), row=2, col=1) + + relayout!(p, showlegend=false, title_text="Specs with Subplot Title") + p +end +with_make_subplots3() +``` + +```@example subplots +function with_make_subplots4() + # Here is an example that uses the `rowspan` and `colspan` subplot options + # to create a custom subplot layout with subplots of mixed sizes. + p = make_subplots( + rows=5, cols=2, + specs=[Spec() Spec(rowspan=2) + Spec() missing + Spec(rowspan=2, colspan=2) missing + missing missing + Spec() Spec()] + ) + + add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(1,1)"), row=1, col=1) + add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(1,2)"), row=1, col=2) + add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(2,1)"), row=2, col=1) + add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(3,1)"), row=3, col=1) + add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(5,1)"), row=5, col=1) + add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(5,2)"), row=5, col=2) + + relayout!(p, height=600, width=600, title_text="specs examples") + p +end +with_make_subplots4() +``` + diff --git a/PlotlyJS/docs/src/examples/tables.md b/PlotlyJS/docs/src/examples/tables.md new file mode 100644 index 0000000..0e2d1ab --- /dev/null +++ b/PlotlyJS/docs/src/examples/tables.md @@ -0,0 +1,113 @@ +# Tables + +```@example tables +using PlotlyJS, DataFrames, CSV, HTTP +``` + +```@example tables +function table1() + values = [ + "Salaries" 1200000 1300000 1300000 1400000 + "Office" 20000 20000 20000 20000 + "Merchandise" 80000 70000 120000 90000 + "Legal" 2000 2000 2000 2000 + "TOTAL" 12120000 130902000 131222000 14102000 + ] + + trace = table( + header=attr( + values=["Expenses", "Q1", "Q2", "Q3", "Q4"], + align="center", line=attr(width=1, color="black"), + fill_color="grey", font=attr(family="Arial", size=12, color="white") + ), + cells=attr( + values=values, align="center", line=attr(color="black", width=1), + font=attr(family="Arial", size=11, color="black") + ) + ) + plot(trace) + +end +table1() +``` + +```@example tables +function table2() + values = [ + "Salaries" 1200000 1300000 1300000 1400000 + "Office" 20000 20000 20000 20000 + "Merchandise" 80000 70000 120000 90000 + "Legal" 2000 2000 2000 2000 + "TOTAL" 12120000 130902000 131222000 14102000 + ] + + trace = table( + header=attr( + values=["EXPENSES", "Q1", "Q2", "Q3", "Q4"], + align=["left", "center"], line=attr(width=1, color="#506784"), + fill_color="#119DFF", + font=attr(family="Arial", size=12, color="white") + ), + cells=attr( + values=values, align=["left", "center"], + line=attr(color="#506784", width=1), + font=attr(family="Arial", size=11, color="#506784"), + fill_color=["#25FEFD", "white"] + ) + ) + plot(trace) + +end +table2() +``` + +```@example tables +function table2a() + p1 = table1() + restyle!(p1, + header=attr( + align=["left", "center"], line_color="#506784", fill_color="#119DFF" + ), + cells=attr( + align=["left", "center"], line_color="#506784", + fill_color=["#25FEFD", "white"], font_color="#506784" + ) + ) + p1 +end +table2a() +``` + +```@example tables +function table3() + url = "https://raw.githubusercontent.com/plotly/datasets/master/Mining-BTC-180.csv" + df = DataFrame(CSV.File(HTTP.get(url).body)) + + trace = table( + columnwidth=[200, 500, 600, 600, 400, 400, 600, 600, 600], + # columnorder=0:9, + header=attr( + values=map(x -> replace(string(x), '_' => '-'), names(df)), + align="center", + line=attr(width=1, color="rgb(50, 50, 50)"), + fill_color=["rgb(235, 100, 230)"], + font=attr(family="Arial", size=12, color="white") + ), + cells=attr( + values=Array(df), + align=["center", "center"], + line=attr(width=1, color="black"), + fill_color=["rgba(228, 222, 249, 0.65)", "rgb(235, 193, 238)", "rgba(228, 222, 249, 0.65)"], + font=attr(family="Arial", size=10, color="black") + ) + ) + + layout = Layout( + title="Bitcoin mining stats for 180 days", + width=1200 + ) + plot(trace, layout) +end +table3() +``` + diff --git a/PlotlyJS/docs/src/examples/ternary.md b/PlotlyJS/docs/src/examples/ternary.md new file mode 100644 index 0000000..b106ed7 --- /dev/null +++ b/PlotlyJS/docs/src/examples/ternary.md @@ -0,0 +1,118 @@ +# Ternary + +```@example ternary +using PlotlyJS, JSON +``` + +```@example ternary +function ternary_markers() + function make_ax(title, tickangle) + attr(title=title, titlefont_size=20, tickangle=tickangle, + tickfont_size=15, tickcolor="rgba(0, 0, 0, 0)", ticklen=5, + showline=true, showgrid=true) + end + + raw_data = [ + Dict(:journalist=>75, :developer=>:25, :designer=>0, :label=>"point 1"), + Dict(:journalist=>70, :developer=>:10, :designer=>20, :label=>"point 2"), + Dict(:journalist=>75, :developer=>:20, :designer=>5, :label=>"point 3"), + Dict(:journalist=>5, :developer=>:60, :designer=>35, :label=>"point 4"), + Dict(:journalist=>10, :developer=>:80, :designer=>10, :label=>"point 5"), + Dict(:journalist=>10, :developer=>:90, :designer=>0, :label=>"point 6"), + Dict(:journalist=>20, :developer=>:70, :designer=>10, :label=>"point 7"), + Dict(:journalist=>10, :developer=>:20, :designer=>70, :label=>"point 8"), + Dict(:journalist=>15, :developer=>:5, :designer=>80, :label=>"point 9"), + Dict(:journalist=>10, :developer=>:10, :designer=>80, :label=>"point 10"), + Dict(:journalist=>20, :developer=>:10, :designer=>70, :label=>"point 11") + ] + + t = scatterternary( + mode="markers", + a=[_x[:journalist] for _x in raw_data], + b=[_x[:developer] for _x in raw_data], + c=[_x[:designer] for _x in raw_data], + text=[_x[:label] for _x in raw_data], + marker=attr(symbol=100, color="#DB7365", size=14, line_width=2) + ) + layout = Layout( + ternary=attr( + sum=100, + aaxis=make_ax("Journalist", 0), + baxis=make_ax("Developer", 45), + caxis=make_ax("Designer", -45), + bgcolor="#fff1e0", + ), annotations=attr( + showarrow=false, + text="Replica of Tom Pearson's block", + x=1.0, y=1.3, font_size=15 + ), + paper_bgcolor="#fff1e0" + ) + plot(t, layout) +end +ternary_markers() +``` + +```@example ternary +function filled_ternary() + function make_ax(title) + attr( + title=title, + ticksuffix="%", + min=0.01, + linewidth=2, + ticks="outside", + ticklen=8, + showgrid=true + ) + end + + fn = tempname() + download("https://gist.githubusercontent.com/davenquinn/988167471993bc2ece29/raw/f38d9cb3dd86e315e237fde5d65e185c39c931c2/data.json", fn) + raw_data = JSON.parsefile(fn) + rm(fn) + + colors = [ + "#8dd3c7", + "#ffffb3", + "#bebada", + "#fb8072", + "#80b1d3", + "#fdb462", + "#b3de69", + "#fccde5", + "#d9d9d9", + "#bc80bd", + "#ccebc5", + "#ffed6f" + ] + + traces = Array{GenericTrace,1}(undef, length(raw_data)) + for (i, (k, v)) in enumerate(raw_data) + traces[i] = scatterternary(mode="lines", name=k, + a=[_x["clay"] for _x in v], + b=[_x["sand"] for _x in v], + c=[_x["silt"] for _x in v], + line_color="#444", + fill="toself", + fillcolor=colors[i], + hoveron="fills+points" + ) + end + layout = Layout( + ternary=attr( + sum=100, + aaxis=make_ax("Clay"), + baxis=make_ax("Sand"), + caxis=make_ax("Slit")), + showlegend=false, + width=700, + annotations=[attr( + showarrow=false, x=0.15, y=1.1, text="Soil types fill plot" + )] + ) + plot(traces, layout) +end +filled_ternary() +``` + diff --git a/PlotlyJS/docs/src/examples/time_series.md b/PlotlyJS/docs/src/examples/time_series.md new file mode 100644 index 0000000..2c409b3 --- /dev/null +++ b/PlotlyJS/docs/src/examples/time_series.md @@ -0,0 +1,14 @@ +# Time Series + +```@example time_series +using PlotlyJS +``` + +```@example time_series +function datetimestrings() + x = ["2013-10-04 22:23:00", "2013-11-04 22:23:00", "2013-12-04 22:23:00"] + plot(scatter(x=x, y=[1 ,3, 6])) +end +datetimestrings() +``` + diff --git a/PlotlyJS/docs/src/examples/violin.md b/PlotlyJS/docs/src/examples/violin.md new file mode 100644 index 0000000..c793f2a --- /dev/null +++ b/PlotlyJS/docs/src/examples/violin.md @@ -0,0 +1,162 @@ +# Violin + +```@example violin +using PlotlyJS, RDatasets, DataFrames +``` + +```@example violin +function violin_box_overlay() + y = abs.(100 .* randn(300)) + data = [ + violin(x0="sample 1", name="violin", y=y, points="all"), + box(x0="sample 1", name="box", y=y, boxpoints=false) + ] + plot(data, Layout(legend=attr(x=0.95, xanchor="right"))) +end +violin_box_overlay() +``` + +```@example violin +function violin_grouped() + days = repeat(["day 1", "day 2"], inner=5) + y_kale = [0.2, 0.2, 0.6, 1, 0.5, 0.4, 0.2, 0.7, 0.9, 0.1, 0.5, 0.3] + y_radish = [0.6, 0.7, 0.3, 0.6, 0, 0.5, 0.7, 0.9, 0.5, 0.8, 0.7, 0.2] + y_carrot = [0.1, 0.3, 0.1, 0.9, 0.6, 0.6, 0.9, 1, 0.3, 0.6, 0.8, 0.5] + colors = ["#3D9970", "#FF4136", "#FF851B"] + names = ["kale", "radishes", "carrots"] + ys = (y_kale, y_radish, y_carrot) + + data = [ + violin( + y=y, name=name, x=days, span=[0, nothing], jitter=0, points="all", + marker=attr(symbol="line-ew", color=color, line=attr(color=color, width=2)) + ) for (y, name, color) in zip(ys, names, colors) + ] + layout = Layout( + yaxis=attr(zeroline=false, title="normalized moisture"), + violinmode="group" + ) + plot(data, layout) +end +violin_grouped() +``` + +```@example violin +function violin_nonlinear() + p1 = plot( + violin( + x=["1798-01-01", "1798-04-04", "1798-05-05", + "1798-05-05", "1798-07-05", "1798-07-22", "1799-01-01"], + orientation="h", box_visible=true, xcalendar="discworld", + name="discworld dates" + ) + ) + p2 = plot( + violin( + x=["A", "B", "C", "C", "C", "D", "G"], + orientation="h", box_visible=true, xcalendar="discworld", + name="categories" + ), Layout(xaxis_categoryarray='A':'G') + ) + p = [p1; p2] + relayout!(p, showlegend=false, margin_l=100) + p +end +violin_nonlinear() +``` + +```@example violin +function violin_old_faithful() + y = [79, 54, 74, 62, 85, 55, 88, 85, 51, 85, 54, 84, 78, 47, 83, 52, 62, + 84, 52, 79, 51, 47, 78, 69, 74, 83, 55, 76, 78, 79, 73, 77, 66, 80, 74, 52, + 48, 80, 59, 90, 80, 58, 84, 58, 73, 83, 64, 53, 82, 59, 75, 90, 54, 80, 54, + 83, 71, 64, 77, 81, 59, 84, 48, 82, 60, 92, 78, 78, 65, 73, 82, 56, 79, 71, + 62, 76, 60, 78, 76, 83, 75, 82, 70, 65, 73, 88, 76, 80, 48, 86, 60, 90, 50, + 78, 63, 72, 84, 75, 51, 82, 62, 88, 49, 83, 81, 47, 84, 52, 86, 81, 75, 59, + 89, 79, 59, 81, 50, 85, 59, 87, 53, 69, 77, 56, 88, 81, 45, 82, 55, 90, 45, + 83, 56, 89, 46, 82, 51, 86, 53, 79, 81, 60, 82, 77, 76, 59, 80, 49, 96, 53, + 77, 77, 65, 81, 71, 70, 81, 93, 53, 89, 45, 86, 58, 78, 66, 76, 63, 88, 52, + 93, 49, 57, 77, 68, 81, 81, 73, 50, 85, 74, 55, 77, 83, 83, 51, 78, 84, 46, + 83, 55, 81, 57, 76, 84, 77, 81, 87, 77, 51, 78, 60, 82, 91, 53, 78, 46, 77, + 84, 49, 83, 71, 80, 49, 75, 64, 76, 53, 94, 55, 76, 50, 82, 54, 75, 78, 79, + 78, 78, 70, 79, 70, 54, 86, 50, 90, 54, 54, 77, 79, 64, 75, 47, 86, 63, 85, + 82, 57, 82, 67, 74, 54, 83, 73, 73, 88, 80, 71, 83, 56, 79, 78, 84, 58, 83, + 43, 60, 75, 81, 46, 90, 46, 74] + plot(violin(y=y, points="all", name="Old Faithful", meanline_visible=true)) +end +violin_old_faithful() +``` + +```@example violin +function violin_side_by_side() + # requires RDatasets and DataFrames + tips = RDatasets.dataset("reshape2", "tips") + parts = zip( + ("Female", "Male"), + ("positive", "negative"), + ("#bebada", "#8dd3c7"), + (1.0, -0.6) + ) + traces = GenericTrace[] + for (sex, side, color, pointpos) in parts + sub_tips = tips[tips[!, :Sex] .== sex, :] + sub_traces = violin(sub_tips, + group=:Day, + x=:TotalBill, y0=(df) -> df[1, :Day], + side=side, orientation="h", + marker=attr(line=attr(width=2, color=color), symbol="line-ns"), + line_color=color, + hoveron="points+kde", text=(df) -> "Sample length $(size(df, 1))", + scalemode="count", scalegroup=sex, legendgroup=sex, name=sex, + points="all", jitter=0, pointpos=pointpos, + span=[0], + box_visible=true, meanline_visible=true, + showlegend=false, + ) + sub_traces[1][:showlegend] = true + append!(traces, sub_traces) + end + # TODO: make the layout + layout = Layout( + hovermode="closest", violinmode="overlay", + title="Total bill distribution
scaled by number of bills per gender", + legend_tracegroupgap=0, violingap=0, violingroupgap=0, + yaxis=attr(showgrid=true, categoryarray=["Thur", "Fri", "Sat", "Sun"]), + ) + plot(traces, layout) +end +violin_side_by_side() +``` + +```@example violin +function violin_style() + y1 = vcat(abs.(20 .* rand(100)), rand(UInt16, 300) .* 500 ./ typemax(UInt16)) + y2 = [25.261999999999997, 66.5419, 98.2114, 0.09070629 ] + box = attr(fillcolor="black", line_color="black", width=0.01) + span = [0, nothing] + trace1 = violin( + bandwidth=5, points=false, y=y1, name="Radial Velocity", + span=span, line_color="#67353E", box=box + ) + trace2 = violin( + bandwidth=5, points=false, y=y2, name="Pulsar Timing", + span=span, line_color="#34ABA2", box=box + ) + + layout = Layout( + paper_bgcolor="#d3d3d3", plot_bgcolor="#d3d3d3", + showlegend=false, violingap=0, xaxis_side="top", + yaxis=attr( + showline=false, showticklabels=false, range=(-5, 550), + zeroline=false, visible=false, showgrid=false, + ), + annotations=[attr( + text="Orbital Period Estimations", font_size=20, + xref="paper", yref="paper", showarrow=false, + )] + ) + plot([trace1, trace2], layout) +end +violin_style() +``` + diff --git a/PlotlyJS/docs/src/index.md b/PlotlyJS/docs/src/index.md new file mode 100644 index 0000000..0e0ae8f --- /dev/null +++ b/PlotlyJS/docs/src/index.md @@ -0,0 +1,52 @@ +# PlotlyJS + +Welcome to the documentation for `PlotlyJS.jl`, a Julia interface to the +[plotly.js](https://plot.ly/javascript) visualization library. + +This package does not interact with the [Plotly web +API](https://api.plot.ly/v2/), but rather leverages the underlying javascript +library to construct plotly graphics using all local resources. This means you +do not need a Plotly account or an internet connection to use this package. + +The goals of `PlotlyJS.jl` are: + +1. Make it convenient to construct and manipulate plotly visualizations +2. Provide infrastructure for viewing plots on multiple frontends and saving +plotly graphics to files + +## Getting Help + +There are three primary resources for getting help with using this library: + +1. The [Julia discourse page](https://discourse.julialang.org/). This is your best option if the question you have is specific to Julia. Appropriate topics include how to integrate with other Julia packages or how to use plotly features unique to `PlotlyJS.jl` +2. The [julia channel](https://community.plotly.com/c/graphing-libraries/julia/23) on the plotly discussion page. This is your best option if you want visibility from other parts of the plotly community including python and R users. +3. [GitHub Issues](https://github.com/JuliaPlots/PlotlyJS.jl/issues). This is appropriate only for bug reports or feature requests. General usage questions should not be posted to GitHub, but rather should utilize one of the discussion forums above + +## Installation + +To install `PlotlyJS.jl`, open up a Julia REPL, press `]` to enter package mode and type: + +```julia +(v1.0) pkg> add PlotlyJS +``` + +For existing users you can run `up` from the package manager REPL mode to get +the latest release. If after doing this plots do not show up in your chosen +frontend, please run `build PlotlyJS` (again from pkg REPL mode) to tell Julia +to download the latest release of the plotly.js javascript library. + +### Saving figures + +`PlotlyJS.jl` comes with built-in support for saving figures to files via the +integration between PlotlyBase.jl (a dependency of `PlotlyJS.jl`) and Plotly's +kaleido tool. + +See [exporting figures](https://juliaplots.org/PlotlyJS.jl/stable/manipulating_plots/#Saving-figures) +for more information. + +### Plots.jl + +If you would like to have a more exhaustive set of top-level functions for +constructing plots, see the [Plots.jl](https://docs.juliaplots.org/latest/) +package. This package is the `plotlyjs` `Plots.jl` backend and is fully supported +by Plots. diff --git a/PlotlyJS/docs/src/manipulating_plots.md b/PlotlyJS/docs/src/manipulating_plots.md new file mode 100644 index 0000000..e85fa64 --- /dev/null +++ b/PlotlyJS/docs/src/manipulating_plots.md @@ -0,0 +1,207 @@ + + +There are various methods defined on the `Plot` type. We will cover a few of +them here, but consult the (forthcoming) API docs for more exhaustive coverage. + +## Julia functions + +`Plot` and `SyncPlot` both have implementations of common Julia methods: + +- `size`: returns the `width` and `layout` attributes in the plot's layout +- `copy`: create a shallow copy of all traces in the plot and the layout, but +create a new `divid` + +## API functions + +All exported functions from the plotly.js +[API](https://plotly.com/javascript/plotlyjs-function-reference/) have been +exposed to Julia and operate on both `Plot` and `SyncPlot` instances. Each of +these functions has semantics that match the semantics of plotly.js + +In `PlotlyJS.jl` these functions are spelled: + +- [`restyle!`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlyrestyle): edit attributes on one or more traces +- [`relayout!`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlyrelayout): edit attributes on the layout +- [`update!`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlyupdate): combination of `restyle!` and `relayout!` +- [`react!`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlyreact): In place updating of all traces and layout in plot. More efficient than constructing an entirely new plot from scratch, but has the same effect. +- [`addtraces!`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlyaddtraces): add traces to a plot at specified indices +- [`deletetraces!`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlydeletetraces): delete specific traces from a plot +- [`movetraces!`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlymovetraces): reorder traces in a plot +- [`redraw!`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlyredraw): for a redraw of an entire plot +- [`purge!`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlypurge): completely remove all data and layout from the chart +- [`extendtraces!`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlyextendtraces): Extend specific attributes of one or more traces with more data by appending to the end of the attribute +- [`prependtraces!`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlyprependtraces): Prepend additional data to specific attributes on one or more traces + + +When any of these routines is called on a `SyncPlot` the underlying `Plot` +object (in the `plot` field on the `SyncPlot`) is updated and the plotly.js +function is called. This is where `SyncPlot` gets its name: when modifying a +plot, it keeps the Julia object and the display in sync. + + + +For more details on which methods are available for each of the above functions +consult the docstrings or (forthcoming) API documentation. + +!!! note + Be especially careful when trying to use `restyle!`, `extendtraces!`, and + `prependtraces!` to set attributes that are arrays. The semantics are a bit + subtle. Check the docstring for details and examples + +## Subplots + +A common task is to construct subpots, or plots with more than one set of axes. +This is possible using the declarative plotly.js syntax, but can be tedious at +best. + +`PlotlyJS.jl` provides a convenient syntax for constructing what we will +call regular grids of subplots. By regular we mean a square grid of plots. + +To do this we will make a pun of the `vcat`, `hcat`, and `hvcat` functions from +`Base` and leverage the array construction syntax to build up our subplots. + +Suppose we are working with the following plots: + +```@repl subplots +using PlotlyJS # hide +p1 = Plot(scatter(;y=randn(3))) +p2 = Plot(histogram(;x=randn(50), nbinsx=4)) +p3 = Plot(scatter(;y=cumsum(randn(12)), name="Random Walk")) +p4 = Plot([scatter(;x=1:4, y=[0, 2, 3, 5], fill="tozeroy"), + scatter(;x=1:4, y=[3, 5, 1, 7], fill="tonexty")]) +``` + +If we wanted to combine `p1` and `p2` as subplots side-by-side, we would do + +```@example subplots +[p1 p2] +``` + +If instead we wanted two rows and one column we could + +```@example subplots +[p3; p4] +``` + +Finally, we can make a 2x2 grid of subplots: + +```@example subplots +[p1 p2 + p3 p4] +``` + +!!! note + New in PlotlyBase version 0.6.5 (PlotlyJS version 0.16.4) + + +As of version 0.16.4, we can also create a non-rectangular grid of subplots using this syntax. + +For example: + +```@example subplots +[p1 p2 p3 p4; p2 p4; p1] +``` + +### `make_subplots` + +!!! note + New in PlotlyBase version 0.6.4 (PlotlyJS version 0.16.3) + +As of version 0.16.3, there is another option for creaing subplots: the `make_subplots` function + +This function takes a number of keyword arguments and allows fine grained control over the layout and labels for subplots. + +Consider the example below: + +```@example subplots +p = make_subplots( + rows=5, cols=2, + specs=[Spec() Spec(rowspan=2) + Spec() missing + Spec(rowspan=2, colspan=2) missing + missing missing + Spec() Spec()] +) + +add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(1,1)"), row=1, col=1) +add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(1,2)"), row=1, col=2) +add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(2,1)"), row=2, col=1) +add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(3,1)"), row=3, col=1) +add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(5,1)"), row=5, col=1) +add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(5,2)"), row=5, col=2) + +relayout!(p, height=600, width=600, title_text="specs examples") +p.plot +``` + +More examples are being worked on at this time (2021-07-14), but for now you can view the docs for [`make_subplots`](@ref) to get an idea of what else is possible. + +## Saving figures + + +Figures can be saved in a variety of formats using the `savefig` function. + +!!! note + Note that the docs below are shown for the `PlotlyBase.Plot` type, but are also defined for `PlotlyJS.SyncPlot`. Thus, you can use these methods after calling either `plot` or `Plot`. + +This function has a few methods: + +**1** + +```@docs +savefig(::Union{PlotlyBase.Plot}, ::String) +``` + +When using this method the format of the file is inferred based on the extension +of the second argument. The examples below show the possible export formats: + +```julia +savefig(p::Union{Plot,SyncPlot}, "output_filename.pdf") +savefig(p::Union{Plot,SyncPlot}, "output_filename.html") +savefig(p::Union{Plot,SyncPlot}, "output_filename.json") +savefig(p::Union{Plot,SyncPlot}, "output_filename.png") +savefig(p::Union{Plot,SyncPlot}, "output_filename.svg") +savefig(p::Union{Plot,SyncPlot}, "output_filename.jpeg") +savefig(p::Union{Plot,SyncPlot}, "output_filename.webp") +``` + +**2** + +```julia +savefig( + io::IO, + p::Plot; + width::Union{Nothing,Int}=nothing, + height::Union{Nothing,Int}=nothing, + scale::Union{Nothing,Real}=nothing, + format::String="png" +) +``` + +This method allows you to save a plot directly to an open IO stream. + +See the [`savefig(::IO, ::PlotlyBase.Plot)`](@ref) API docs for more information. + +**3** + +```julia +Base.show(::IO, ::MIME, ::Union{PlotlyBase.Plot}) +``` + +This method hooks into Julia's rich display system. + +Possible arguments for the second argument are shown in the examples below: + +```julia +savefig(io::IO, ::MIME"application/pdf", p::Union{Plot,SyncPlot}) +savefig(io::IO, ::MIME"image/png", p::Union{Plot,SyncPlot}) +savefig(io::IO, ::MIME"image/svg+xml", p::Union{Plot,SyncPlot}) +savefig(io::IO, ::MIME"image/eps", p::Union{Plot,SyncPlot}) +savefig(io::IO, ::MIME"image/jpeg", p::Union{Plot,SyncPlot}) +savefig(io::IO, ::MIME"application/json", p::Union{Plot,SyncPlot}) +savefig(io::IO, ::MIME"application/json; charset=UTF-8", p::Union{Plot,SyncPlot}) +``` + +!!! note + You can also save the json for a figure by calling + `savejson(p::Union{Plot,SyncPlot}, filename::String)`. diff --git a/PlotlyJS/docs/src/syncplots.md b/PlotlyJS/docs/src/syncplots.md new file mode 100644 index 0000000..9a48d22 --- /dev/null +++ b/PlotlyJS/docs/src/syncplots.md @@ -0,0 +1,176 @@ +# Putting it Together + +```@meta +CurrentModule = PlotlyJS +``` + +We will now look at how to combine traces and a layout to create a plot. + +We'll also discuss how to integrate with various frontends. + +## `Plot` + +Recall that the definition of the `Plot` object is + +```julia +mutable struct Plot{TT<:AbstractVector{<:AbstractTrace},TL<:AbstractLayout,TF<:AbstractVector{<:PlotlyFrame}} + data::TT + layout::TL + frames::TF + divid::UUID + config::PlotConfig +end +``` + +Given one or more `AbstractTrace`s and optionally a `Layout`, we construct a +`Plot` object with any of the following constructors + +```julia +# A blank canvas no traces or a layout +Plot() + +# A vector of traces and a layout +Plot{T<:AbstractTrace}(data::AbstractVector{T}, layout::AbstractLayout) + +# A vector of traces -- default layout supplied +Plot{T<:AbstractTrace}(data::AbstractVector{T}) + +# a single trace: will be put into a vector -- default layout supplied +Plot(data::AbstractTrace) + +# a single trace and a layout (trace put into a vector) +Plot(data::AbstractTrace, layout::AbstractLayout) +``` + +Notice that none of the recommended constructors have you pass the `divid` +field manually. This is an internal field used to allow the display and +unique identification of multiple plots in a single web page. + +### [Convenience methods](@id constructors) + +There are also a number of convenience methods to the `Plot` function that will +attempt to construct the traces for you. They have the following signatures + +```@docs +PlotlyBase.Plot +``` + +Especially convenient is the `group` keyword argument when calling +`Plot(::AbstractDataFrame, ... ; ...)`. Here is an example below: + +```@example iris_group +using PlotlyJS # hide +using RDatasets +iris = RDatasets.dataset("datasets", "iris"); +p = Plot(iris, x=:SepalLength, y=:SepalWidth, mode="markers", marker_size=8, group=:Species) +``` + +## `SyncPlot`s + +A `Plot` is a pure Julia object and doesn't interact with plotly.js by itself. +This means that we can't view the actual plotly figure the data represents. + +To do that we need to link the `Plot` to one or more display frontends. + +To actually connect to the display frontends we use the +[WebIO.jl](https://github.com/JuliaGizmos/WebIO.jl) package. Our interaction +with WebIO is wrapped up in a type called `SyncPlot` that is defined as +follows: + +```julia +mutable struct SyncPlot + plot::PlotlyBase.Plot + scope::Scope + window::Union{Nothing,Blink.Window} +end +``` + +As its name suggests, a `SyncPlot` will keep the Julia representation of the a +plot (the `Plot` instance) in sync with a plot with a frontend. + +!!! note + The `Plot` function will create a new `Plot` object and the `plot` function + will create a new `SyncPlot`. The `plot` function passes all arguments + to construct a `Plot` and then sets up the display. All `Plot` methods are also defined for `plot` + +By leveraging WebIO.jl we can render our figures anywhere WebIO can render. At +time of writing this includes [Jupyter notebooks](https://jupyter.org/), +[Jupyterlab](https://github.com/jupyterlab/jupyterlab), +[Mux.jl](https://github.com/JuliaWeb/Mux.jl) web apps, the +[Juno](https://junolab.org/) Julia environment inside the Atom text editor, and +Electron windows from [Blink.jl](https://github.com/JuliaGizmos/Blink.jl). Please +see the [WebIO.jl readme](https://github.com/JuliaGizmos/WebIO.jl) for +additional (and up to date!) information. + +When using `PlotlyJS.jl` at the Julia REPL a plot will automatically be displayed +in an Electron window. This is a dedicated browser window we have full control +over. To see a plot `p`, just type `p` by itself at the REPL and execute the +line. Alternatively you can call `display(p)`. + +In addition to being able to see our charts in many front-end environments, +WebIO also provides a 2-way communication bridge between javascript and Julia. +In fact, when a `SyncPlot` is constructed, we automatically get listeners for +all [plotly.js javascript events](https://plotly.com/javascript/plotlyjs-events/). +What's more is that we can hook up Julia functions as callbacks when those +events are triggered. In the very contrived example below we have Julia print +out details regarding points on a plot whenever a user hovers over them on the +display: + +```julia +using WebIO +p = plot(rand(10, 4)); +display(p) # usually optional + +on(p["hover"]) do data + println("\nYou hovered over", data) +end +``` + +In this next example, whenever we click on a point we change its marker symbol +to a star and marker color to gold: + +```julia +using WebIO +colors = (fill("red", 10), fill("blue", 10)) +symbols = (fill("circle", 10), fill("circle", 10)) +ys = (rand(10), rand(10)) +p = plot( + [scatter(y=y, marker=attr(color=c, symbol=s, size=15), line_color=c[1]) + for (y, c, s) in zip(ys, colors, symbols)] +) +display(p) # usually optional + +on(p["click"]) do data + colors = (fill("red", 10), fill("blue", 10)) + symbols = (fill("circle", 10), fill("circle", 10)) + for point in data["points"] + colors[point["curveNumber"] + 1][point["pointIndex"] + 1] = "gold" + symbols[point["curveNumber"] + 1][point["pointIndex"] + 1] = "star" + end + restyle!(p, marker_color=colors, marker_symbol=symbols) +end +``` + +While completely nonsensical, hopefully these examples show you that it is +possible to build rich, interactive, web-based data visualization applications +with business logic implemented entirely in Julia!. + +### Display configuration + +!!! note + New in PlotlyBase version 0.6.4 (PlotlyJS version 0.16.3) + + +When calling `plot` or `Plot`, we can specify some configuration options using the `config` keyword argument. + +The `config` argument must be set to an instance of `PlotConfig`, which should be constructed using keyword arguments. + +As an example, if we were to execute the following code, we would see a static +chart (no hover information or ability to zoom/pan) with 4 lines instead of an +interactive one: + +```example plot_config +Plot(rand(10, 4), config=PlotConfig(staticPlot=true)) +``` + +See the API docs for [`PlotConfig`](@ref) for a full list of options. diff --git a/PlotlyJS/examples/3d.jl b/PlotlyJS/examples/3d.jl new file mode 100644 index 0000000..051cf73 --- /dev/null +++ b/PlotlyJS/examples/3d.jl @@ -0,0 +1,242 @@ +using PlotlyJS, DataFrames, RDatasets, Colors, Distributions, LinearAlgebra + +function random_line() + n = 400 + rw() = cumsum(randn(n)) + trace1 = scatter3d(;x=rw(),y=rw(), z=rw(), mode="lines", + marker=attr(color="#1f77b4", size=12, symbol="circle", + line=attr(color="rgb(0,0,0)", width=0)), + line=attr(color="#1f77b4", width=1)) + trace2 = scatter3d(;x=rw(),y=rw(), z=rw(), mode="lines", + marker=attr(color="#9467bd", size=12, symbol="circle", + line=attr(color="rgb(0,0,0)", width=0)), + line=attr(color="rgb(44, 160, 44)", width=1)) + trace3 = scatter3d(;x=rw(),y=rw(), z=rw(), mode="lines", + marker=attr(color="#bcbd22", size=12, symbol="circle", + line=attr(color="rgb(0,0,0)", width=0)), + line=attr(color="#bcbd22", width=1)) + layout = Layout(autosize=false, width=500, height=500, + margin=attr(l=0, r=0, b=0, t=65)) + plot([trace1, trace2, trace3], layout) +end + +function topo_surface() + z = Vector[[27.80985, 49.61936, 83.08067, 116.6632, 130.414, 150.7206, 220.1871, + 156.1536, 148.6416, 203.7845, 206.0386, 107.1618, 68.36975, 45.3359, + 49.96142, 21.89279, 17.02552, 11.74317, 14.75226, 13.6671, 5.677561, + 3.31234, 1.156517, -0.147662], + [27.71966, 48.55022, 65.21374, 95.27666, 116.9964, 133.9056, 152.3412, + 151.934, 160.1139, 179.5327, 147.6184, 170.3943, 121.8194, 52.58537, + 33.08871, 38.40972, 44.24843, 69.5786, 4.019351, 3.050024, 3.039719, + 2.996142, 2.967954, 1.999594], + [30.4267, 33.47752, 44.80953, 62.47495, 77.43523, 104.2153, 102.7393, 137.0004, + 186.0706, 219.3173, 181.7615, 120.9154, 143.1835, 82.40501, 48.47132, + 74.71461, 60.0909, 7.073525, 6.089851, 6.53745, 6.666096, 7.306965, 5.73684, + 3.625628], + [16.66549, 30.1086, 39.96952, 44.12225, 59.57512, 77.56929, 106.8925, + 166.5539, 175.2381, 185.2815, 154.5056, 83.0433, 62.61732, 62.33167, + 60.55916, 55.92124, 15.17284, 8.248324, 36.68087, 61.93413, 20.26867, + 68.58819, 46.49812, 0.2360095], + [8.815617, 18.3516, 8.658275, 27.5859, 48.62691, 60.18013, 91.3286, + 145.7109, 116.0653, 106.2662, 68.69447, 53.10596, 37.92797, 47.95942, + 47.42691, 69.20731, 44.95468, 29.17197, 17.91674, 16.25515, 14.65559, + 17.26048, 31.22245, 46.71704], + [6.628881, 10.41339, 24.81939, 26.08952, 30.1605, 52.30802, 64.71007, + 76.30823, 84.63686, 99.4324, 62.52132, 46.81647, 55.76606, 82.4099, + 140.2647, 81.26501, 56.45756, 30.42164, 17.28782, 8.302431, 2.981626, + 2.698536, 5.886086, 5.268358], + [21.83975, 6.63927, 18.97085, 32.89204, 43.15014, 62.86014, 104.6657, + 130.2294, 114.8494, 106.9873, 61.89647, 55.55682, 86.80986, 89.27802, + 122.4221, 123.9698, 109.0952, 98.41956, 77.61374, 32.49031, 14.67344, + 7.370775, 0.03711011, 0.6423392], + [53.34303, 26.79797, 6.63927, 10.88787, 17.2044, 56.18116, 79.70141, + 90.8453, 98.27675, 80.87243, 74.7931, 75.54661, 73.4373, 74.11694, 68.1749, + 46.24076, 39.93857, 31.21653, 36.88335, 40.02525, 117.4297, 12.70328, + 1.729771, 0], + [25.66785, 63.05717, 22.1414, 17.074, 41.74483, 60.27227, 81.42432, 114.444, + 102.3234, 101.7878, 111.031, 119.2309, 114.0777, 110.5296, 59.19355, + 42.47175, 14.63598, 6.944074, 6.944075, 27.74936, 0, 0, 0.09449376, 0.07732264], + [12.827, 69.20554, 46.76293, 13.96517, 33.88744, 61.82613, 84.74799, + 121.122, 145.2741, 153.1797, 204.786, 227.9242, 236.3038, 228.3655, + 79.34425, 25.93483, 6.944074, 6.944074, 6.944075, 7.553681, 0, 0, 0, 0], + [0, 68.66396, 59.0435, 33.35762, 47.45282, 57.8355, 78.91689, 107.8275, + 168.0053, 130.9597, 212.5541, 165.8122, 210.2429, 181.1713, 189.7617, + 137.3378, 84.65395, 8.677168, 6.956576, 8.468093, 0, 0, 0, 0], + [0, 95.17499, 80.03818, 59.89862, 39.58476, 50.28058, 63.81641, 80.61302, + 66.37824, 198.7651, 244.3467, 294.2474, 264.3517, 176.4082, 60.21857, + 77.41475, 53.16981, 56.16393, 6.949235, 7.531059, 3.780177, 0, 0, 0], + [0, 134.9879, 130.3696, 96.86325, 75.70494, 58.86466, 57.20374, 55.18837, + 78.128, 108.5582, 154.3774, 319.1686, 372.8826, 275.4655, 130.2632, 54.93822, + 25.49719, 8.047439, 8.084393, 5.115252, 5.678269, 0, 0, 0], + [0, 48.08919, 142.5558, 140.3777, 154.7261, 87.9361, 58.11092, 52.83869, + 67.14822, 83.66798, 118.9242, 150.0681, 272.9709, 341.1366, 238.664, 190.2, + 116.8943, 91.48672, 14.0157, 42.29277, 5.115252, 0, 0, 0], + [0, 54.1941, 146.3839, 99.48143, 96.19411, 102.9473, 76.14089, 57.7844, + 47.0402, 64.36799, 84.23767, 162.7181, 121.3275, 213.1646, 328.482, + 285.4489, 283.8319, 212.815, 164.549, 92.29631, 7.244015, 1.167, 0, 0], + [0, 6.919659, 195.1709, 132.5253, 135.2341, 89.85069, 89.45549, 60.29967, + 50.33806, 39.17583, 59.06854, 74.52159, 84.93402, 187.1219, 123.9673, + 103.7027, 128.986, 165.1283, 249.7054, 95.39966, 10.00284, 2.39255, 0, 0], + [0, 21.73871, 123.1339, 176.7414, 158.2698, 137.235, 105.3089, 86.63255, 53.11591, + 29.03865, 30.40539, 39.04902, 49.23405, 63.27853, 111.4215, 101.1956, + 40.00962, 59.84565, 74.51253, 17.06316, 2.435141, 2.287471, -0.0003636982, 0], + [0, 0, 62.04672, 136.3122, 201.7952, 168.1343, 95.2046, 58.90624, 46.94091, + 49.27053, 37.10416, 17.97011, 30.93697, 33.39257, 44.03077, 55.64542, + 78.22423, 14.42782, 9.954997, 7.768213, 13.0254, 21.73166, 2.156372, + 0.5317867], + [0, 0, 79.62993, 139.6978, 173.167, 192.8718, 196.3499, 144.6611, 106.5424, + 57.16653, 41.16107, 32.12764, 13.8566, 10.91772, 12.07177, 22.38254, + 24.72105, 6.803666, 4.200841, 16.46857, 15.70744, 33.96221, 7.575688, + -0.04880907], + [0, 0, 33.2664, 57.53643, 167.2241, 196.4833, 194.7966, 182.1884, 119.6961, + 73.02113, 48.36549, 33.74652, 26.2379, 16.3578, 6.811293, 6.63927, 6.639271, + 8.468093, 6.194273, 3.591233, 3.81486, 8.600739, 5.21889, 0], + [0, 0, 29.77937, 54.97282, 144.7995, 207.4904, 165.3432, 171.4047, 174.9216, + 100.2733, 61.46441, 50.19171, 26.08209, 17.18218, 8.468093, 6.63927, + 6.334467, 6.334467, 5.666687, 4.272203, 0, 0, 0, 0], + [0, 0, 31.409, 132.7418, 185.5796, 121.8299, 185.3841, 160.6566, 116.1478, + 118.1078, 141.7946, 65.56351, 48.84066, 23.13864, 18.12932, 10.28531, + 6.029663, 6.044627, 5.694764, 3.739085, 3.896037, 0, 0, 0], + [0, 0, 19.58994, 42.30355, 96.26777, 187.1207, 179.6626, 221.3898, 154.2617, + 142.1604, 148.5737, 67.17937, 40.69044, 39.74512, 26.10166, 14.48469, + 8.65873, 3.896037, 3.571392, 3.896037, 3.896037, 3.896037, 1.077756, 0], + [0.001229679, 3.008948, 5.909858, 33.50574, 104.3341, 152.2165, 198.1988, + 191.841, 228.7349, 168.1041, 144.2759, 110.7436, 57.65214, 42.63504, + 27.91891, 15.41052, 8.056102, 3.90283, 3.879774, 3.936718, 3.968634, + 0.1236256, 3.985531, -0.1835741], + [0, 5.626141, 7.676256, 63.16226, 45.99762, 79.56688, 227.311, 203.9287, + 172.5618, 177.1462, 140.4554, 123.9905, 110.346, 65.12319, 34.31887, + 24.5278, 9.561069, 3.334991, 5.590495, 5.487353, 5.909499, 5.868994, + 5.833817, 3.568177]] + trace = surface(z=z) + layout = Layout(title="Mt. Bruno Elevation", autosize=false, width=500, + height=500, margin=attr(l=65, r=50, b=65, t=90)) + plot(trace, layout) +end + +function multiple_surface() + z1 = Vector[[8.83, 8.89, 8.81, 8.87, 8.9, 8.87], + [8.89, 8.94, 8.85, 8.94, 8.96, 8.92], + [8.84, 8.9, 8.82, 8.92, 8.93, 8.91], + [8.79, 8.85, 8.79, 8.9, 8.94, 8.92], + [8.79, 8.88, 8.81, 8.9, 8.95, 8.92], + [8.8, 8.82, 8.78, 8.91, 8.94, 8.92], + [8.75, 8.78, 8.77, 8.91, 8.95, 8.92], + [8.8, 8.8, 8.77, 8.91, 8.95, 8.94], + [8.74, 8.81, 8.76, 8.93, 8.98, 8.99], + [8.89, 8.99, 8.92, 9.1, 9.13, 9.11], + [8.97, 8.97, 8.91, 9.09, 9.11, 9.11], + [9.04, 9.08, 9.05, 9.25, 9.28, 9.27], + [9, 9.01, 9, 9.2, 9.23, 9.2], + [8.99, 8.99, 8.98, 9.18, 9.2, 9.19], + [8.93, 8.97, 8.97, 9.18, 9.2, 9.18]] + z2 = map(x -> x .+ 1, z1) + z3 = map(x -> x .- 1, z1) + trace1 = surface(z=z1, colorscale="Viridis") + trace2 = surface(z=z2, showscale=false, opacity=0.9, colorscale="Viridis") + trace3 = surface(z=z3, showscale=false, opacity=0.9, colorscale="Viridis") + plot([trace1, trace2, trace3]) +end + +function clustering_alpha_shapes() + # load data + iris = RDatasets.dataset("datasets", "iris") + nms = unique(iris.Species) + colors = [RGB(0.89, 0.1, 0.1), RGB(0.21, 0.50, 0.72), RGB(0.28, 0.68, 0.3)] + + data = GenericTrace[] + + for (i, nm) in enumerate(nms) + df = iris[iris[!, :Species] .== nm, :] + x = df[!, :SepalLength] + y = df[!, :SepalWidth] + z = df[!, :PetalLength] + trace = scatter3d(;name=nm, mode="markers", + marker_size=3, marker_color=colors[i], marker_line_width=0, + x=x, y=y, z=z) + push!(data, trace) + + cluster = mesh3d(;color=colors[i], opacity=0.3, x=x, y=y, z=z) + push!(data, cluster) + end + + # notice the nested attrs to create complex JSON objects + layout = Layout(width=800, height=550, autosize=false, title="Iris dataset", + scene=attr(xaxis=attr(gridcolor="rgb(255, 255, 255)", + zerolinecolor="rgb(255, 255, 255)", + showbackground=true, + backgroundcolor="rgb(230, 230,230)"), + yaxis=attr(gridcolor="rgb(255, 255, 255)", + zerolinecolor="rgb(255, 255, 255)", + showbackground=true, + backgroundcolor="rgb(230, 230,230)"), + zaxis=attr(gridcolor="rgb(255, 255, 255)", + zerolinecolor="rgb(255, 255, 255)", + showbackground=true, + backgroundcolor="rgb(230, 230,230)"), + aspectratio=attr(x=1, y=1, z=0.7), + aspectmode="manual")) + plot(data, layout) +end + +function scatter_3d() + Σ = fill(0.5, 3, 3) + Diagonal([0.5, 0.5, 0.5]) + obs1 = rand(MvNormal(zeros(3), Σ), 200)' + obs2 = rand(MvNormal(zeros(3), 0.5Σ), 100)' + + trace1 = scatter3d(;x=obs1[:, 1], y=obs1[:, 2], z=obs1[:, 3], + mode="markers", opacity=0.8, + marker_size=12, marker_line_width=0.5, + marker_line_color="rgba(217, 217, 217, 0.14)") + + trace2 = scatter3d(;x=obs2[:, 1], y=obs2[:, 2], z=obs2[:, 3], + mode="markers", opacity=0.9, + marker=attr(color="rgb(127, 127, 127)", + symbol="circle", line_width=1.0, + line_color="rgb(204, 204, 204)")) + + layout = Layout(margin=attr(l=0, r=0, t=0, b=0)) + + plot([trace1, trace2], layout) +end + + +function trisurf() + facecolor = repeat([ + "rgb(50, 200, 200)", + "rgb(100, 200, 255)", + "rgb(150, 200, 115)", + "rgb(200, 200, 50)", + "rgb(230, 200, 10)", + "rgb(255, 140, 0)" + ], inner=[2]) + + t = mesh3d( + x=[0, 0, 1, 1, 0, 0, 1, 1], + y=[0, 1, 1, 0, 0, 1, 1, 0], + z=[0, 0, 0, 0, 1, 1, 1, 1], + i=[7, 0, 0, 0, 4, 4, 2, 6, 4, 0, 3, 7], + j=[3, 4, 1, 2, 5, 6, 5, 5, 0, 1, 2, 2], + k=[0, 7, 2, 3, 6, 7, 1, 2, 5, 5, 7, 6], + facecolor=facecolor) + + plot(t) +end + +function meshcube() + t = mesh3d( + x=[0, 0, 1, 1, 0, 0, 1, 1], + y=[0, 1, 1, 0, 0, 1, 1, 0], + z=[0, 0, 0, 0, 1, 1, 1, 1], + i=[7, 0, 0, 0, 4, 4, 6, 6, 4, 0, 3, 2], + j=[3, 4, 1, 2, 5, 6, 5, 2, 0, 1, 6, 3], + k=[0, 7, 2, 3, 6, 7, 1, 1, 5, 5, 7, 6], + intensity=range(0, stop=1, length=8), + colorscale=[ + [0, "rgb(255, 0, 255)"], + [0.5, "rgb(0, 255, 0)"], + [1, "rgb(0, 0, 255)"] + ] + ) + plot(t) +end diff --git a/PlotlyJS/examples/area.jl b/PlotlyJS/examples/area.jl new file mode 100644 index 0000000..5a67b3f --- /dev/null +++ b/PlotlyJS/examples/area.jl @@ -0,0 +1,33 @@ +using PlotlyJS + +function area1() + trace1 = scatter(;x=1:4, y=[0, 2, 3, 5], fill="tozeroy") + trace2 = scatter(;x=1:4, y=[3, 5, 1, 7], fill="tonexty") + plot([trace1, trace2]) +end + +function area2() + function _stacked_area!(traces) + for (i, tr) in enumerate(traces[2:end]) + for j in 1:min(length(traces[i]["y"]), length(tr["y"])) + tr["y"][j] += traces[i]["y"][j] + end + end + traces + end + + traces = [scatter(;x=1:3, y=[2, 1, 4], fill="tozeroy"), + scatter(;x=1:3, y=[1, 1, 2], fill="tonexty"), + scatter(;x=1:3, y=[3, 0, 2], fill="tonexty")] + _stacked_area!(traces) + + plot(traces, Layout(title="stacked and filled line chart")) +end + + +function area3() + trace1 = scatter(;x=1:4, y=[0, 2, 3, 5], fill="tozeroy", mode="none") + trace2 = scatter(;x=1:4, y=[3, 5, 1, 7], fill="tonexty", mode="none") + plot([trace1, trace2], + Layout(title="Overlaid Chart Without Boundary Lines")) +end diff --git a/PlotlyJS/examples/bar.jl b/PlotlyJS/examples/bar.jl new file mode 100644 index 0000000..aa42b68 --- /dev/null +++ b/PlotlyJS/examples/bar.jl @@ -0,0 +1,224 @@ +using PlotlyJS + +function bar1() + data = bar(;x=["giraffes", "orangutans", "monkeys"], + y=[20, 14, 23]) + plot(data) +end + +function bar2() + trace1 = bar(;x=["giraffes", "orangutans", "monkeys"], + y=[20, 14, 23], + name="SF Zoo") + trace2 = bar(;x=["giraffes", "orangutans", "monkeys"], + y=[12, 18, 29], + name="LA Zoo") + data = [trace1, trace2] + layout = Layout(;barmode="group") + plot(data, layout) +end + +function bar3() + trace1 = bar(;x=["giraffes", "orangutans", "monkeys"], + y=[20, 14, 23], + name="SF Zoo") + trace2 = bar(x=["giraffes", "orangutans", "monkeys"], + y=[12, 18, 29], + name="LA Zoo") + data = [trace1, trace2] + layout = Layout(;barmode="stack") + plot(data, layout) +end + +function bar4() + data = bar(;x=["Product A", "Product B", "Product C"], + y=[20, 14, 23], + text=["$(i)% market share" for i in rand(15:30, 3)], + marker=attr(color="rgb(158, 202, 225)", opacity=0.6), + line=attr(color="rgb(8, 48, 107)", width=1.5)) + + layout = Layout(;title="January 2013 Sales Report") + + plot(data, layout) +end + +function bar5() + x_value = ["Product A", "Product B", "Product C"] + y_value = [20, 14, 23] + + data = bar(;x=x_value, + y=y_value, + text=["$(i)% market share" for i in rand(15:30, 3)], + marker=attr(color="rgb(158, 202, 225)", opacity=0.6, + line=attr(color="rgb(8, 48, 107)", width=1.5))) + + annotations = [] + + for i in 1:length(x_value) + result = attr(x=x_value[i], + y=y_value[i], + text=y_value[i], + xanchor="center", + yanchor="bottom", + showarrow=false) + push!(annotations, result) + end + + layout = Layout(;title="January 2013 Sales Report", + annotations=annotations) + plot(data, layout) +end + +function bar6() + trace1 = bar(;x=["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec"], + y=[20, 14, 25, 16, 18, 22, 19, 15, 12, 16, 14, 17], + name="Primary Product", + marker_color="rgb(49, 130, 189)", + opacity=0.7) + trace2 = bar(;x=["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec"], + y=[19, 14, 22, 14, 16, 19, 15, 14, 10, 12, 12, 16], + name="Secondary Product", + marker=attr(color="rgb(204, 204, 204)", opacity=0.5)) + data = [trace1, trace2] + layout = Layout(;title="2013 Sales Report", + xaxis_tickangle=-45, + barmode="group") + plot(data, layout) +end + +function bar7() + data = bar(;x=["Feature $(s)" for s in 'A':'E'], + y=[20, 14, 23, 25, 22], + marker_color=["rgba(204, 204, 204, 1)", + "rgba(222, 45, 38, 0.8)", + "rgba(204, 204, 204, 1)", + "rgba(204, 204, 204, 1)", + "rgba(204, 204, 204, 1)"]) + layout = Layout(;title="Least Used Feature") + plot(data, layout) +end + +function bar8() + data = bar(;x=["Liam", "Sophie", "Jacob", "Mia", "William", "Olivia"], + y=[8.0, 8.0, 12.0, 12.0, 13.0, 20.0], + text=["4.17 below the mean", "4.17 below the mean", + "0.17 below the mean", "0.17 below the mean", + "0.83 above the mean", "7.83 above the mean"], + marker_color="rgb(142, 124, 195)") + layout = Layout(;title="Number of Graphs Made this Week", + font_family="Raleway, sans-serif", + showlegend=false, + xaxis_tickangle=-45, + yaxis=attr(zeroline=false, gridwidth=2), + bargap=0.05) + plot(data, layout) +end + +function bar9() + trace1 = bar(;x=1995:2012, + y=[219, 146, 112, 127, 124, 180, 236, 207, 236, 263, 350, + 430, 474, 526, 488, 537, 500, 439], + name="Rest of world", + marker_color="rgb(55, 83, 109)") + trace2 = bar(;x=1995:2012, + y=[16, 13, 10, 11, 28, 37, 43, 55, 56, 88, 105, 156, 270, + 299, 340, 403, 549, 499], + name="China", + marker_color="rgb(26, 118, 255)") + + data = [trace1, trace2] + + layout = Layout(;title="US Export of Plastic Scrap", + xaxis=attr(tickfont_size= 14, + tickfont_color="rgb(107, 107, 107)"), + yaxis=attr(title="USD (millions)", + titlefont=attr(size=16, + color="rgb(107, 107, 107)"), + tickfont=attr(size=14, + color="rgb(107, 107, 107)")), + legend=attr(x=0, y=1.0, bgcolor="rgba(255, 255, 255, 0)", + bordercolor="rgba(255, 255, 255, 0)"), + barmode="group", + bargap=0.15, + bargroupgap=0.1) + plot(data, layout) +end + +function bar10() + x_data = ["Product Revenue", "Services Revenue", "Total Revenue", + "Fixed Costs", "Variable Costs", "Total Costs", "Total"] + y_data = [400, 660, 660, 590, 400, 400, 340] + textList = ["\$430K", "\$260K", "\$690K", "\$-120K", "\$-200K", "\$-320K", + "\$370K"] + + #Base + trace1 = bar(;x=x_data, + y=[0, 430, 0, 570, 370, 370, 0], + marker_color="rgba(1, 1, 1, 0.0)") + + #Revenue + trace2 = bar(;x=x_data, + y=[430, 260, 690, 0, 0, 0, 0], + marker_color="rgba(55, 128, 191, 0.7)", + line=attr(color="rgba(55, 128, 191, 1.0)", width=2)) + + #Cost + trace3 = bar(;x=x_data, + y=[0, 0, 0, 120, 200, 320, 0], + marker=attr(color="rgba(219, 64, 82, 0.7)", + line=attr(color="rgba(219, 64, 82, 1.0)", width=2))) + + #Profit + trace4 = bar(;x=x_data, + y=[0, 0, 0, 0, 0, 0, 370], + marker=attr(color="rgba(50, 171, 96, 0.7)", + line=attr(color="rgba(50, 171, 96, 1.0)", width=2))) + + data = [trace1, trace2, trace3, trace4] + + annotations = [] + for i in 1:7 + result = attr(x=x_data[i], + y=y_data[i], + text=textList[i], + font=attr(;family="Arial", font_size=14, + font_color="rgba(245, 246, 249, 1)"), + showarrow=false) + push!(annotations, result) + end + + layout = Layout(;title="Annual Profit 2015", + barmode="stack", + paper_bgcolor="rgba(245, 246, 249, 1)", + plot_bgcolor="rgba(245, 246, 249, 1)", + width=600, + height=600, + showlegend=false, + xaxis_showtickabels=true, + annotations=annotations) + + plot(data, layout) +end + +function bar11() + trace1 = bar(;x=[1, 2, 3, 4], + y=[1, 4, 9, 16], + name="Trace1") + trace2 = bar(;x=[1, 2, 3, 4], + y=[6, -8, -4.5, 8], + name="Trace2") + trace3 = bar(;x=[1, 2, 3, 4], + y=[-15, -3, 4.5, -8], + name="Trace3") + trace4 = bar(;x=[1, 2, 3, 4], + y=[-1, 3, -3, -4], + name="Trace4") + data = [trace1, trace2, trace3, trace4] + layout = Layout(;xaxis_title="X axis", + yaxis_title="Y axis", + barmode="relative", + title="Relative Barmode") + plot(data, layout) +end diff --git a/PlotlyJS/examples/box_plots.jl b/PlotlyJS/examples/box_plots.jl new file mode 100644 index 0000000..295777f --- /dev/null +++ b/PlotlyJS/examples/box_plots.jl @@ -0,0 +1,222 @@ +using PlotlyJS + +function box1() + y0 = rand(50) + y1 = rand(50) .+ 1 + trace1 = box(;y=y0) + trace2 = box(;y=y1) + data = [trace1, trace2] + plot(data) +end + +function box2() + data = box(;y=[0, 1, 1, 2, 3, 5, 8, 13, 21], + boxpoints="all", + jitter=0.3, + pointpos=-1.8) + plot(data) +end + + +function box3() + trace1 = box(;x=[1, 2, 3, 4, 4, 4, 8, 9, 10], + name="Set 1") + trace2 = box(;x=[2, 3, 3, 3, 3, 5, 6, 6, 7], + name="Set 2") + data = [trace1, trace2] + layout = Layout(;title="Horizontal Box Plot") + + plot(data, layout) +end + + +function box4() + x0 = ["day 1", "day 1", "day 1", "day 1", "day 1", "day 1", + "day 2", "day 2", "day 2", "day 2", "day 2", "day 2"] + trace1 = box(;y=[0.2, 0.2, 0.6, 1.0, 0.5, 0.4, 0.2, 0.7, 0.9, 0.1, 0.5, 0.3], + x=x0, + name="kale", + marker_color="#3D9970") + trace2 = box(;y=[0.6, 0.7, 0.3, 0.6, 0.0, 0.5, 0.7, 0.9, 0.5, 0.8, 0.7, 0.2], + x=x0, + name="radishes", + marker_color="#FF4136") + trace3 = box(;y=[0.1, 0.3, 0.1, 0.9, 0.6, 0.6, 0.9, 1.0, 0.3, 0.6, 0.8, 0.5], + x=x0, + name="carrots", + marker_color="#FF851B") + data = [trace1, trace2, trace3] + layout = Layout(;yaxis=attr(title="normalized moisture", zeroline=false), + boxmode="group") + plot(data, layout) +end + + +function box5() + trace1 = box(;y=[0.75, 5.25, 5.5, 6, 6.2, 6.6, 6.80, 7.0, 7.2, 7.5, 7.5, + 7.75, 8.15, 8.15, 8.65, 8.93, 9.2, 9.5, 10, 10.25, 11.5, + 12, 16, 20.90, 22.3, 23.25], + name="All Points", + jitter=0.3, + pointpos=-1.8, + marker_color="rgb(7, 40, 89)", + boxpoints="all") + trace2 = box(;y=[0.75, 5.25, 5.5, 6, 6.2, 6.6, 6.80, 7.0, 7.2, 7.5, 7.5, + 7.75, 8.15, 8.15, 8.65, 8.93, 9.2, 9.5, 10, 10.25, 11.5, + 12, 16, 20.90, 22.3, 23.25], + name="Only Wiskers", + marker_color="rgb(9, 56, 125)", + boxpoints=false) + trace3 = box(;y=[0.75, 5.25, 5.5, 6, 6.2, 6.6, 6.80, 7.0, 7.2, 7.5, 7.5, + 7.75, 8.15, 8.15, 8.65, 8.93, 9.2, 9.5, 10, 10.25, 11.5, + 12, 16, 20.90, 22.3, 23.25], + name="Suspected Outlier", + marker=attr(color="rgb(8, 8, 156)", + outliercolor="rgba(219, 64, 82, 0.6)", + line=attr(outliercolor="rgba(219, 64, 82, 1.0)", + outlierwidth=2)), + boxpoints="suspectedoutliers") + trace4 = box(;y=[0.75, 5.25, 5.5, 6, 6.2, 6.6, 6.80, 7.0, 7.2, 7.5, 7.5, + 7.75, 8.15, 8.15, 8.65, 8.93, 9.2, 9.5, 10, 10.25, 11.5, + 12, 16, 20.90, 22.3, 23.25], + name="Wiskers and Outliers", + marker_color="rgb(107, 174, 214)", + boxpoints="Outliers") + data = [trace1, trace2, trace3, trace4] + layout = Layout(;title="Box Plot Styling Outliers") + plot(data, layout) +end + + +function box6() + trace1 = box(;y=[2.37, 2.16, 4.82, 1.73, 1.04, 0.23, 1.32, 2.91, 0.11, + 4.51, 0.51, 3.75, 1.35, 2.98, 4.50, 0.18, 4.66, 1.30, + 2.06, 1.19], + name="Only Mean", + marker_color="rgb(8, 81, 156)", + boxmean=true) + trace2 = box(;y=[2.37, 2.16, 4.82, 1.73, 1.04, 0.23, 1.32, 2.91, 0.11, + 4.51, 0.51, 3.75, 1.35, 2.98, 4.50, 0.18, 4.66, 1.30, + 2.06, 1.19], + name="Mean and Standard Deviation", + marker_color="rgb(10, 140, 208)", + boxmean="sd") + data = [trace1, trace2] + layout = Layout(;title="Box Plot Styling Mean and Standard Deviation") + plot(data, layout) +end + + +function box7() + y0 = ["day 1", "day 1", "day 1", "day 1", "day 1", "day 1", + "day 2", "day 2", "day 2", "day 2", "day 2", "day 2"] + trace1 = box(;x=[0.2, 0.2, 0.6, 1.0, 0.5, 0.4, 0.2, 0.7, 0.9, 0.1, 0.5, 0.3], + y=y0, + name="kale", + marker_color="#3D9970", + boxmean=false, + orientation="h") + trace2 = box(;x=[0.6, 0.7, 0.3, 0.6, 0.0, 0.5, 0.7, 0.9, 0.5, 0.8, 0.7, 0.2], + y=y0, + name="radishes", + marker_color="#FF4136", + boxmean=false, + orientation="h") + trace3 = box(;x=[0.1, 0.3, 0.1, 0.9, 0.6, 0.6, 0.9, 1.0, 0.3, 0.6, 0.8, 0.5], + y=y0, + name="carrots", + marker_color="#FF851B", + boxmean=false, + orientation="h") + data = [trace1, trace2, trace3] + layout = Layout(;title="Grouped Horizontal Box Plot", + xaxis=attr(title="normalized moisture", zeroline=false), + boxmode="group") + plot(data, layout) +end + + +function box8() + trace1 = box(;y=[1, 2, 3, 4, 4, 4, 8, 9, 10], + name="Sample A", + marker_color="rgb(214, 12, 140)") + trace2 = box(;y=[2, 3, 3, 3, 3, 5, 6, 6, 7], + name="Sample B", + marker_color="rgb(0, 128, 128)") + data = [trace1, trace2] + layout = Layout(;title="Colored Box Plot") + plot(data, layout) +end + +function box9() + xData = ["Carmelo
Anthony", "Dwyane
Wade", "Deron
Williams", + "Brook
Lopez", "Damian
Lillard", "David
West", + "Blake
Griffin", "David
Lee", "Demar
Derozan"] + + _getrandom(num, mul) = mul .* rand(num) + + yData = Array[ + _getrandom(30, 10), + _getrandom(30, 20), + _getrandom(30, 25), + _getrandom(30, 40), + _getrandom(30, 45), + _getrandom(30, 30), + _getrandom(30, 20), + _getrandom(30, 15), + _getrandom(30, 43) + ] + colors = ["rgba(93, 164, 214, 0.5)", "rgba(255, 144, 14, 0.5)", + "rgba(44, 160, 101, 0.5)", "rgba(255, 65, 54, 0.5)", + "rgba(207, 114, 255, 0.5)", "rgba(127, 96, 0, 0.5)", + "rgba(255, 140, 184, 0.5)", "rgba(79, 90, 117, 0.5)", + "rgba(222, 223, 0, 0.5)"] + + data = GenericTrace[] + for i in 1:length(xData) + trace = box(;y=yData[i], + name=xData[i], + boxpoints="all", + jitter=0.5, + whiskerwidth=0.2, + fillcolor="cls", + marker_size=2, + line_width=1) + push!(data, trace) + end + + t = "Points Scored by the Top 9 Scoring NBA Players in 2012" + layout = Layout(;title=t, + yaxis=attr(autorange=true, showgrid=true, zeroline=true, + dtick=5, gridcolor="rgb(255, 255, 255)", + gridwidth=1, + zerolinecolor="rgb(255, 255, 255)", + zerolinewidth=2), + margin=attr(l=40, r=30, b=80, t=100), + paper_bgcolor="rgb(243, 243, 243)", + plot_bgcolor="rgb(243, 243, 243)", + showlegend=false) + plot(data, layout) +end + +function box10() + n_box = 30 + colors = ["hsl($i, 50%, 50%)" for i in range(0, stop=360, length=n_box)] + + gen_y_data(i) = + (3.5*sin(pi*i/n_box) + i/n_box) .+ (1.5+0.5*cos(pi*i/n_box)).*rand(10) + + ys = Array[gen_y_data(i) for i in 1:n_box] + + # Create Traces + data = GenericTrace[box(y=y, marker_color=mc) for (y, mc) in zip(ys, colors)] + + #Format the layout + layout = Layout(;xaxis=attr(;showgrid=false, zeroline=false, + tickangle=60, showticklabels=true), + yaxis=attr(;zeroline=false, gridcolor="white"), + paper_bgcolor="rgb(233, 233, 233)", + plot_bgcolor="rgb(233, 233, 233)", + showlegend=true) + plot(data, layout) +end diff --git a/PlotlyJS/examples/contour.jl b/PlotlyJS/examples/contour.jl new file mode 100644 index 0000000..ed78466 --- /dev/null +++ b/PlotlyJS/examples/contour.jl @@ -0,0 +1,207 @@ +using PlotlyJS + +function contour1() + x = y = [-2*pi + 4*pi*i/100 for i in 1:100] + z = [sin(x[i]) * cos(y[j]) * sin(x[i]*x[i]+y[j]*y[j])/log(x[i]*x[i]+y[j]*y[j]+1) + for i in 1:100 for j in 1:100] + z_ = [z[i:i+99] for i in 1:100:10000] + + data = contour(;z=z_, x=x, y=y) + + plot(data) +end + +function contour2() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z) + + layout = Layout(;title="Basic Contour Plot") + plot(data, layout) +end + +function contour3() + x = [-9, -6, -5 , -3, -1] + y = [0, 1, 4, 5, 7] + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + trace = contour(x=x, y=y, z=z) + + layout = Layout(title="Setting the X and Y Coordinates in a Contour Plot") + plot(trace, layout) +end + +function contour4() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, colorscale="Jet") + + layout = Layout(;title="Colorscale for Contour Plot") + plot(data, layout) +end + +function contour5() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, + colorscale="Jet", + autocontour=false, + contours=Dict(:start=>0, :end=>8, :size=>2)) + + layout = Layout(;title="Customizing Size and Range of Contours") + plot(data, layout) +end + +function contour6() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, colorscale="Jet", dx=10, x0=5, dy=10, y0=10) + + layout = Layout(;title="Customizing Spacing Between X and Y Axis Ticks") + + plot(data, layout) +end + +function contour7() + z = [NaN NaN NaN 12 13 14 15 16 + NaN 1 NaN 11 NaN NaN NaN 17 + NaN 2 6 7 NaN NaN NaN 18 + NaN 3 NaN 8 NaN NaN NaN 19 + 5 4 10 9 NaN NaN NaN 20 + NaN NaN NaN 27 NaN NaN NaN 21 + NaN NaN NaN 26 25 24 23 22]' + + p1 = plot(contour(;z=z, showscale=false)) + p2 = plot(contour(;z=z, connectgaps=true, showscale=false)) + p3 = plot(heatmap(;z=z, zsmooth="best",showscale=false)) + p4 = plot(heatmap(;z=z, zsmooth="best", connectgaps=true, showscale=false)) + + p = [p1 p2; p3 p4] + + relayout!(p, title="Connect the Gaps Between Null Values in the Z Matrix") + + p +end + +function contour8() + z = [2 4 7 12 13 14 15 16 + 3 1 6 11 12 13 16 17 + 4 2 7 7 11 14 17 18 + 5 3 8 8 13 15 18 19 + 7 4 10 9 16 18 20 19 + 9 10 5 27 23 21 21 21 + 11 14 17 26 25 24 23 22] + + p1 = plot(contour(;z=z, line_smoothing=0)) + p2 = plot(contour(;z=z, line_smoothing=0.85)) + + p = [p1 p2] + + relayout!(p, title="Smoothing Contour Lines") + + p +end + +function contour9() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, contours_coloring="heatmap") + + layout = Layout(;title="Smooth Contour Coloring") + plot(data, layout) +end + +function contour10() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, colorscale="Jet", contours_coloring="lines") + + layout = Layout(;title="Contour Lines") + plot(data, layout) +end + +function contour11() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, + colorscale=[[0, "rgb(166,206,227)"], + [0.25, "rgb(31,120,180)"], + [0.45, "rgb(178,223,138)"], + [0.64, "rgb(51,160,44)"], + [0.85, "rgb(251,154,153)"], + [1, "rgb(227,26,28)"]]) + + layout = Layout(;title="Custom Contour Plot Colorscale") + + plot(data, layout) +end + +function contour12() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, + colorbar=attr(;title="Color Bar Title",titleside="right", + titlefont=attr(;size=14, + family="Arial, sans-serif"))) + + layout = Layout(;title="Colorbar with Title") + plot(data,layout) +end + +function contour13() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, + colorbar=attr(;thickness=75, thicknessmode="pixels", + len=0.9, lenmode="fraction", + outlinewidth=0)) + + layout = Layout(;title="Colorbar Size for Contour Plots") + plot(data,layout) +end + +function contour14() + z = [10 10.625 12.5 15.625 20 + 5.625 6.25 8.125 11.25 15.625 + 2.5 3.125 5. 8.125 12.5 + 0.625 1.25 3.125 6.25 10.625 + 0 0.625 2.5 5.625 10] + data = contour(;z=z, + colorbar=attr(;ticks="outside", dtick=1, + tickwidth=2, ticklen=10, + tickcolor="grey", showticklabels=true, + tickfont_size=15, xpad=50)) + + layout = Layout(;title="Styling Color Bar Ticks for Contour Plots") + plot(data,layout) +end diff --git a/PlotlyJS/examples/finance.jl b/PlotlyJS/examples/finance.jl new file mode 100644 index 0000000..ede3a16 --- /dev/null +++ b/PlotlyJS/examples/finance.jl @@ -0,0 +1,43 @@ +using PlotlyJS, HTTP, CSV, DataFrames + +function ohlc1() + t = ohlc(open=[33.0, 33.3, 33.5, 33.0, 34.1], + high=[33.1, 33.3, 33.6, 33.2, 34.8], + low=[32.7, 32.7, 32.8, 32.6, 32.8], + close=[33.0, 32.9, 33.3, 33.1, 33.1]) + plot(t) +end + +function ohlc2() + function get_ohlc(ticker; kwargs...) + res = HTTP.get("https://www.quandl.com/api/v3/datasets/WIKI/$(ticker)/data.csv?start_date=2017-01-01") + df = DataFrame(CSV.File(res.body)) + ohlc(df, x=:Date, open=:Open, high=:High, low=:Low, close=:Close; kwargs...) + end + + p1 = plot(get_ohlc("AAPL", name="Apple"), Layout(title="Apple")) + p2 = plot(get_ohlc("GOOG", name="Google"), Layout(title="Google")) + + [p1 p2] +end + +function candlestick1() + t = candlestick(open=[33.0, 33.3, 33.5, 33.0, 34.1], + high=[33.1, 33.3, 33.6, 33.2, 34.8], + low=[32.7, 32.7, 32.8, 32.6, 32.8], + close=[33.0, 32.9, 33.3, 33.1, 33.1]) + plot(t) +end + +function candlestick2() + function get_candlestick(ticker; kwargs...) + res = HTTP.get("https://www.quandl.com/api/v3/datasets/WIKI/$(ticker)/data.csv?start_date=2017-01-01") + df = DataFrame(CSV.File(res.body)) + candlestick(df, x=:Date, open=:Open, high=:High, low=:Low, close=:Close; kwargs...) + end + + p1 = plot(get_candlestick("AAPL", name="Apple"), Layout(title="Apple")) + p2 = plot(get_candlestick("GOOG", name="Google"), Layout(title="Google")) + + [p1 p2] +end diff --git a/PlotlyJS/examples/heatmaps.jl b/PlotlyJS/examples/heatmaps.jl new file mode 100644 index 0000000..f3698cc --- /dev/null +++ b/PlotlyJS/examples/heatmaps.jl @@ -0,0 +1,15 @@ +using PlotlyJS, Random +Random.seed!(42) + +function heatmap1() + plot(heatmap(z=[1 20 30; 20 1 60; 30 60 1])) +end + +function heatmap2() + trace = heatmap( + x=["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"], + y=["Morning", "Afternoon", "Evening"], + z=rand(1:30, 5, 3) + ) + plot(trace) +end diff --git a/PlotlyJS/examples/histograms.jl b/PlotlyJS/examples/histograms.jl new file mode 100644 index 0000000..e9a528f --- /dev/null +++ b/PlotlyJS/examples/histograms.jl @@ -0,0 +1,12 @@ +using PlotlyJS + +function two_hists() + x0 = randn(500) + x1 = x0 .+ 1 + + trace1 = histogram(x=x0, opacity=0.75) + trace2 = histogram(x=x1, opacity=0.75) + data = [trace1, trace2] + layout = Layout(barmode="overlay") + plot(data, layout) +end diff --git a/PlotlyJS/examples/interactions.ipynb b/PlotlyJS/examples/interactions.ipynb new file mode 100644 index 0000000..c2f88d7 --- /dev/null +++ b/PlotlyJS/examples/interactions.ipynb @@ -0,0 +1,484 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + " \n", + "

Plotly javascript loaded.

\n", + "

To load again call

init_notebook(true)

\n", + " " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "using PlotlyJS" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": "{\"layout\":{\"width\":330,\"margin\":{\"r\":50,\"l\":50,\"b\":50,\"t\":60},\"height\":200},\"data\":[{\"y\":[0,2,3,5],\"type\":\"scatter\",\"x\":[1,2,3,4],\"fill\":\"tozeroy\"},{\"y\":[3,5,1,7],\"type\":\"scatter\",\"x\":[1,2,3,4],\"fill\":\"tonexty\"}]}", + "text/html": [ + "
\n", + "\n", + "\n" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "trace1 = scatter(;x=1:4, y=[0, 2, 3, 5], fill=\"tozeroy\")\n", + "trace2 = scatter(;x=1:4, y=[3, 5, 1, 7], fill=\"tonexty\")\n", + "p2 = plot([trace1, trace2], Layout(height=200, width=330))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `restyle!`" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# second trace will turn pink\n", + "restyle!(p2, 2; marker_color=\"magenta\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# watch both markers change to squares\n", + "restyle!(p2, [1,2]; marker_symbol=\"square\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# simpler method without passing [1,2]\n", + "restyle!(p2; marker_symbol=\"star-triangle-up-open\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `relayout!`" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "relayout!(p2; width=400, height=250)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "relayout!(p2; title=\"Interactively controlled!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `addtraces!`" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "trace3 = scatter(;x=1:4, y=rand(1:10, 4), fill=\"tozeroy\")\n", + "addtraces!(p2, trace3)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Add one to the front of the stack. will appear on bottom of legend\n", + "# Notice it \n", + "trace4 = scatter(;x=1:4, y=rand(1:10, 4), fill=\"tozeroy\", marker_color=\"yellow\")\n", + "addtraces!(p2, 1, trace4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `deletetraces!`" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "deletetraces!(p2, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "deletetraces!(p2, 1) # back to where we started :)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `movetraces!`" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# swap the order of the traces (move trace at index 1 to the back)\n", + "movetraces!(p2, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# swap them back\n", + "movetraces!(p2, [2, 1], [1, 2])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that the plot object also changed so everything was kept in sync:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "layout with fields height, margin, title, and width\n" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p2.plot.layout" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "scatter with fields fill, marker, type, x, and y\n" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p2.plot.data[1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Non-mutating variants\n", + "\n", + "For each of the functions `restyle!`, `relayout!`, `addtraces!`, `deletetraces!`, and `movetraces!` there is also a non-mutating version with the same name, but without the `!`. These will create a copy of the underlying data, perform the given transformation, and return a new object. \n", + "\n", + "You can tell the object is new because a new plot appears:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": "{\"layout\":{\"width\":400,\"xaxis\":{\"title\":\"new title\"},\"title\":\"Interactively controlled!\",\"margin\":{\"r\":50,\"l\":50,\"b\":50,\"t\":60},\"height\":250},\"data\":[{\"y\":[3,5,1,7],\"type\":\"scatter\",\"x\":[1,2,3,4],\"fill\":\"tonexty\",\"marker\":{\"symbol\":\"star-triangle-up-open\",\"color\":\"magenta\"}},{\"y\":[0,2,3,5],\"type\":\"scatter\",\"x\":[1,2,3,4],\"fill\":\"tozeroy\",\"marker\":{\"symbol\":\"star-triangle-up-open\"}}]}", + "text/html": [ + "
\n", + "\n", + "\n" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p3 = relayout(p2; xaxis_title=\"new title\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 0.5.0", + "language": "julia", + "name": "julia-0.5" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "0.5.0" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/PlotlyJS/examples/line_scatter.jl b/PlotlyJS/examples/line_scatter.jl new file mode 100644 index 0000000..e9b1bb0 --- /dev/null +++ b/PlotlyJS/examples/line_scatter.jl @@ -0,0 +1,301 @@ +using PlotlyJS, DataFrames, CSV, Dates, HTTP + +function linescatter1() + trace1 = scatter(;x=1:4, y=[10, 15, 13, 17], mode="markers") + trace2 = scatter(;x=2:5, y=[16, 5, 11, 9], mode="lines") + trace3 = scatter(;x=1:4, y=[12, 9, 15, 12], mode="lines+markers") + plot([trace1, trace2, trace3]) +end + +function linescatter2() + trace1 = scatter(;x=1:5, y=[1, 6, 3, 6, 1], + mode="markers", name="Team A", + text=["A-1", "A-2", "A-3", "A-4", "A-5"], + marker_size=12) + + trace2 = scatter(;x=1:5 + 0.5, y=[4, 1, 7, 1, 4], + mode="markers", name="Team B", + text=["B-a", "B-b", "B-c", "B-d", "B-e"]) + # setting marker.size this way is _equivalent_ to what we did for trace1 + trace2["marker"] = Dict(:size => 12) + + data = [trace1, trace2] + layout = Layout(;title="Data Labels Hover", xaxis_range=[0.75, 5.25], + yaxis_range=[0, 8]) + plot(data, layout) +end + +function linescatter3() + trace1 = scatter(;x=1:5, y=[1, 6, 3, 6, 1], + mode="markers+text", name="Team A", + textposition="top center", + text=["A-1", "A-2", "A-3", "A-4", "A-5"], + marker_size=12, textfont_family="Raleway, sans-serif") + + trace2 = scatter(;x=1:5 + 0.5, y=[4, 1, 7, 1, 4], + mode="markers+text", name="Team B", + textposition="bottom center", + text=["B-a", "B-b", "B-c", "B-d", "B-e"], + marker_size=12, textfont_family="Times New Roman") + + data = [trace1, trace2] + + layout = Layout(;title="Data Labels on the Plot", xaxis_range=[0.75, 5.25], + yaxis_range=[0, 8], legend_y=0.5, legend_yref="paper", + legend=attr(family="Arial, sans-serif", size=20, + color="grey")) + plot(data, layout) +end + +function linescatter4() + trace1 = scatter(;y=fill(5, 40), mode="markers", marker_size=40, + marker_color=0:39) + layout = Layout(title="Scatter Plot with a Color Dimension") + plot(trace1, layout) +end + +function linescatter5() + + country = ["Switzerland (2011)", "Chile (2013)", "Japan (2014)", + "United States (2012)", "Slovenia (2014)", "Canada (2011)", + "Poland (2010)", "Estonia (2015)", "Luxembourg (2013)", + "Portugal (2011)"] + + votingPop = [40, 45.7, 52, 53.6, 54.1, 54.2, 54.5, 54.7, 55.1, 56.6] + regVoters = [49.1, 42, 52.7, 84.3, 51.7, 61.1, 55.3, 64.2, 91.1, 58.9] + + # notice use of `attr` function to make nested attributes + trace1 = scatter(;x=votingPop, y=country, mode="markers", + name="Percent of estimated voting age population", + marker=attr(color="rgba(156, 165, 196, 0.95)", + line_color="rgba(156, 165, 196, 1.0)", + line_width=1, size=16, symbol="circle")) + + trace2 = scatter(;x=regVoters, y=country, mode="markers", + name="Percent of estimated registered voters") + # also could have set the marker props above by using a dict + trace2["marker"] = Dict(:color => "rgba(204, 204, 204, 0.95)", + :line => Dict(:color => "rgba(217, 217, 217, 1.0)", + :width => 1), + :symbol => "circle", + :size => 16) + + data = [trace1, trace2] + layout = Layout(Dict{Symbol,Any}(:paper_bgcolor => "rgb(254, 247, 234)", + :plot_bgcolor => "rgb(254, 247, 234)"); + title="Votes cast for ten lowest voting age population in OECD countries", + width=600, height=600, hovermode="closest", + margin=Dict(:l => 140, :r => 40, :b => 50, :t => 80), + xaxis=attr(showgrid=false, showline=true, + linecolor="rgb(102, 102, 102)", + titlefont_color="rgb(204, 204, 204)", + tickfont_color="rgb(102, 102, 102)", + autotick=false, dtick=10, ticks="outside", + tickcolor="rgb(102, 102, 102)"), + legend=attr(font_size=10, yanchor="middle", + xanchor="right"), + ) + plot(data, layout) +end + +function linescatter6() + trace1 = scatter(;x=[52698, 43117], y=[53, 31], + mode="markers", + name="North America", + text=["United States", "Canada"], + marker=attr(color="rgb(164, 194, 244)", size=12, + line=attr(color="white", width=0.5)) + ) + + trace2 = scatter(;x=[39317, 37236, 35650, 30066, 29570, 27159, 23557, 21046, 18007], + y=[33, 20, 13, 19, 27, 19, 49, 44, 38], + mode="markers", name="Europe", + marker_size=12, marker_color="rgb(255, 217, 102)", + text=["Germany", "Britain", "France", "Spain", "Italy", + "Czech Rep.", "Greece", "Poland", "Portugal"]) + + trace3 = scatter(;x=[42952, 37037, 33106, 17478, 9813, 5253, 4692, 3899], + y=[23, 42, 54, 89, 14, 99, 93, 70], + mode="markers", + name="Asia/Pacific", + marker_size=12, marker_color="rgb(234, 153, 153)", + text=["Australia", "Japan", "South Korea", "Malaysia", + "China", "Indonesia", "Philippines", "India"]) + + trace4 = scatter(;x=[19097, 18601, 15595, 13546, 12026, 7434, 5419], + y=[43, 47, 56, 80, 86, 93, 80], + mode="markers", name="Latin America", + marker_size=12, marker_color="rgb(142, 124, 195)", + text=["Chile", "Argentina", "Mexico", "Venezuela", + "Venezuela", "El Salvador", "Bolivia"]) + + data = [trace1, trace2, trace3, trace4] + + layout = Layout(;title="Quarter 1 Growth", + xaxis=attr(title="GDP per Capital", showgrid=false, zeroline=false), + yaxis=attr(title="Percent", zeroline=false)) + + plot(data, layout) +end + +function batman() + # reference: https://github.com/alanedelman/18.337_2015/blob/master/Lecture01_0909/The%20Bat%20Curve.ipynb + σ(x) = @. √(1 - x.^2) + el(x) = @. 3 * σ(x / 7) + s(x) = @. 4.2 - 0.5 * x - 2.0 * σ(0.5 * x - 0.5) + b(x) = @. σ(abs(2 - x) - 1) - x.^2 / 11 + 0.5x - 3 + c(x) = [1.7, 1.7, 2.6, 0.9] + + p(i, f; kwargs...) = scatter(;x=[-i; 0.0; i], y=[f(i); NaN; f(i)], + marker_color="black", showlegend=false, + kwargs...) + traces = vcat(p(3:0.1:7, el; name="wings 1"), + p(4:0.1:7, t -> -el(t); name="wings 2"), + p(1:0.1:3, s; name="Shoulders"), + p(0:0.1:4, b; name="Bottom"), + p([0, 0.5, 0.8, 1], c; name="head")) + + plot(traces, Layout(title="Batman")) +end + +function dumbell() + # reference: https://plot.ly/r/dumbbell-plots/ + # read Data into dataframe + url = "https://raw.githubusercontent.com/plotly/datasets/master/school_earnings.csv" + df = DataFrame(CSV.File(HTTP.get(url).body)) + + # sort dataframe by male earnings + df = sort(df, :Men, rev=false) + + men = scatter(;y=df.School, x=df.Men, mode="markers", name="Men", + marker=attr(color="blue", size=12)) + women = scatter(;y=df.School, x=df.Women, mode="markers", name="Women", + marker=attr(color="pink", size=12)) + + lines = map(eachrow(df)) do r + scatter(y=fill(r.School, 2), x=[r.Women, r.Men], mode="lines", + name=r.School, showlegend=false, line_color="gray") + end + + data = Base.typed_vcat(GenericTrace, men, women, lines) + layout = Layout(width=650, height=650, margin_l=100, yaxis_title="School", + xaxis_title="Annual Salary (thousands)", + title="Gender earnings disparity") + + plot(data, layout) +end + +function errorbars1() + trace1 = scatter(;x=vcat(1:10, 10:-1:1), + y=vcat(2:11, 9:-1:0), + fill="tozerox", + fillcolor="rgba(0, 100, 80, 0.2)", + line_color="transparent", + name="Fair", + showlegend=false) + + trace2 = scatter(;x=vcat(1:10, 10:-1:1), + y=[5.5, 3.0, 5.5, 8.0, 6.0, 3.0, 8.0, 5.0, 6.0, 5.5, 4.75, + 5.0, 4.0, 7.0, 2.0, 4.0, 7.0, 4.4, 2.0, 4.5], + fill="tozerox", + fillcolor="rgba(0, 176, 246, 0.2)", + line_color="transparent", + name="Premium", + showlegend=false) + + trace3 = scatter(;x=vcat(1:10, 10:-1:1), + y=[11.0, 9.0, 7.0, 5.0, 3.0, 1.0, 3.0, 5.0, 3.0, 1.0, + -1.0, 1.0, 3.0, 1.0, -0.5, 1.0, 3.0, 5.0, 7.0, 9.], + fill="tozerox", + fillcolor="rgba(231, 107, 243, 0.2)", + line_color="transparent", + name="Fair", + showlegend=false) + + trace4 = scatter(;x=1:10, y=1:10, + line_color="rgb(00, 100, 80)", + mode="lines", + name="Fair") + + trace5 = scatter(;x=1:10, + y=[5.0, 2.5, 5.0, 7.5, 5.0, 2.5, 7.5, 4.5, 5.5, 5.], + line_color="rgb(0, 176, 246)", + mode="lines", + name="Premium") + + trace6 = scatter(;x=1:10, y=vcat(10:-2:0, [2, 4,2, 0]), + line_color="rgb(231, 107, 243)", + mode="lines", + name="Ideal") + data = [trace1, trace2, trace3, trace4, trace5, trace6] + layout = Layout(;paper_bgcolor="rgb(255, 255, 255)", + plot_bgcolor="rgb(229, 229, 229)", + + xaxis=attr(gridcolor="rgb(255, 255, 255)", + range=[1, 10], + showgrid=true, + showline=false, + showticklabels=true, + tickcolor="rgb(127, 127, 127)", + ticks="outside", + zeroline=false), + + yaxis=attr(gridcolor="rgb(255, 255, 255)", + showgrid=true, + showline=false, + showticklabels=true, + tickcolor="rgb(127, 127, 127)", + ticks="outside", + zeroline=false)) + + plot(data, layout) +end + +function errorbars2() + function random_dates(d1::DateTime, d2::DateTime, n::Int) + map(Date, sort!(rand(d1:Dates.Hour(12):d2, n))) + end + + function _random_number(num, mul) + value = [] + j = 0 + rand = 0 + while j <= num + 1 + rand = rand() * mul + append!(value, [rand]) + j += 1 + end + return value + end + + dates = random_dates(DateTime(2001, 1, 1), DateTime(2005, 12, 31), 50) + + trace1 = scatter(;x=dates, + y=20.0 .* rand(50), + line_width=0, + marker_color="444", + mode="lines", + name="Lower Bound") + + trace2 = scatter(;x=dates, + y=21.0 .* rand(50), + fill="tonexty", + fillcolor="rgba(68, 68, 68, 0.3)", + line_color="rgb(31, 119, 180)", + mode="lines", + name="Measurement") + + trace3 = scatter(;x=dates, + y=22.0 .* rand(50), + fill="tonexty", + fillcolor="rgba(68, 68, 68, 0.3)", + line_width=0, + marker_color="444", + mode="lines", + name="Upper Bound") + + data = [trace1, trace2, trace3] + t = "Continuous, variable value error bars
Notice the hover text!" + layout = Layout(;title=t, yaxis_title="Wind speed (m/s)") + plot(data, layout) +end diff --git a/PlotlyJS/examples/maps.jl b/PlotlyJS/examples/maps.jl new file mode 100644 index 0000000..c491343 --- /dev/null +++ b/PlotlyJS/examples/maps.jl @@ -0,0 +1,43 @@ +using PlotlyJS, DataFrames, CSV, HTTP + +function maps1() + marker = attr(size=[20, 30, 15, 10], + color=[10, 20, 40, 50], + cmin=0, + cmax=50, + colorscale="Greens", + colorbar=attr(title="Some rate", + ticksuffix="%", + showticksuffix="last"), + line_color="black") + trace = scattergeo(;mode="markers", locations=["FRA", "DEU", "RUS", "ESP"], + marker=marker, name="Europe Data") + layout = Layout(geo_scope="europe", geo_resolution=50, width=500, height=550, + margin=attr(l=0, r=0, t=10, b=0)) + plot(trace, layout) +end + +function maps2() + # read Data into dataframe + url = "https://raw.githubusercontent.com/plotly/datasets/master/2014_us_cities.csv" + df = DataFrame(CSV.File(HTTP.get(url).body)) + + trace = scattergeo(;locationmode="USA-states", + lat=df.lat, + lon=df.lon, + hoverinfo="text", + text=[string(x.name, " pop: ", x.pop) for x in eachrow(df)], + marker_size=df.pop ./ 50_000, + marker_line_color="black", marker_line_width=2) + geo = attr(scope="usa", + projection_type="albers usa", + showland=true, + landcolor="rgb(217, 217, 217)", + subunitwidth=1, + countrywidth=1, + subunitcolor="rgb(255,255,255)", + countrycolor="rgb(255,255,255)") + + layout = Layout(;title="2014 US City Populations", showlegend=false, geo=geo) + plot(trace, layout) +end diff --git a/PlotlyJS/examples/shapes.jl b/PlotlyJS/examples/shapes.jl new file mode 100644 index 0000000..8fcc331 --- /dev/null +++ b/PlotlyJS/examples/shapes.jl @@ -0,0 +1,135 @@ +using PlotlyJS, Distributions + +function house() + trace1 = scatter() + x0 = [2, 2, 5.5, 9, 9, 2, 5, 5, 6] + y0 = [1, 5.5, 9.5, 5.5, 1, 5.5, 1, 4, 4] + x1 = [2, 5.5, 9, 9, 2, 9, 5, 6, 6] + y1 = [5.5, 9.5, 5.5, 1, 1, 5.5, 4, 4, 1] + shapes = line(x0, x1, y0, y1; xref="x", yref="y") + plot([trace1], + Layout(;shapes=shapes, xaxis_range=(1, 10), yaxis_range=(0, 10))) +end + +function house2() + trace1 = scatter() + _p = string("M 2 1 L 2 5.5 L 5.5 9.6 L 9 5.5 L 9 1 L 2 1 ", + "M 2 5.5 L 9 5.5 ", + "M 5 1 L 5 4 L 6 4 L 6 1 Z") + plot([trace1], + Layout(;shapes=[path(_p)], xaxis_range=(1, 10), yaxis_range=(0, 10))) +end + +function clusters() + x0 = rand(Normal(2, 0.45), 300) + y0 = rand(Normal(2, 0.45), 300) + x1 = rand(Normal(6, 0.4), 200) + y1 = rand(Normal(6, 0.4), 200) + x2 = rand(Normal(4, 0.3), 200) + y2 = rand(Normal(4, 0.3), 200) + + data = [scatter(;x=x0, y=y0, mode="markers"), + scatter(;x=x1, y=y1, mode="markers"), + scatter(;x=x2, y=y2, mode="markers"), + scatter(;x=x1, y=y0, mode="markers")] + + args = [(x0, y0, "blue"), (x1, y1, "orange"), (x2, y2, "green"), + (x1, y0, "red")] + shapes = [circle(x0=minimum(x), y0=minimum(y), + x1=maximum(x), y1=maximum(y); + opacity=0.2, fillcolor=c, line_color=c) + for (x, y, c) in args] + plot(data, Layout(;height=400, width=480, showlegend=false, shapes=shapes)) +end + +function temperature() + x = ["2015-02-01", "2015-02-02", "2015-02-03", "2015-02-04", "2015-02-05", + "2015-02-06", "2015-02-07", "2015-02-08", "2015-02-09", "2015-02-10", + "2015-02-11", "2015-02-12", "2015-02-13", "2015-02-14", "2015-02-15", + "2015-02-16", "2015-02-17", "2015-02-18", "2015-02-19", "2015-02-20", + "2015-02-21", "2015-02-22", "2015-02-23", "2015-02-24", "2015-02-25", + "2015-02-26", "2015-02-27", "2015-02-28"] + y = rand(1:20, length(x)) + data = scatter(;x=x, y=y, name="temperature", mode="line") + + shapes = rect(["2015-02-04", "2015-02-20"], ["2015-02-06", "2015-02-22"], + 0, 1; fillcolor="#d3d3d3", opacity=0.2, line_width=0, + xref="x", yref="paper") + plot(data, Layout(shapes=shapes, width=500, height=500)) +end + +function vlines1() + # one scalar argument produces one line. Need to wrap in an array because + # layout.shapes should be an array + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = [vline(2)] + plot([trace1], Layout(;shapes=shapes)) +end + +function vlines2() + # one argument draws a vertical line up the entire plot + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = vline([2, 6]) + plot([trace1], Layout(;shapes=shapes)) +end + +function vlines3() + # yref paper makes the 2nd and 3rd arguments on a (0, 1) scale vertically + # so 0.5 is 1/2 through the plot regardless of the values on y-axis + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = vline([2, 6], 0, 0.5; yref="paper") + plot([trace1], Layout(;shapes=shapes)) +end + +function vlines4() + # Whichever argument is a scalar is repeated + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = vline([2, 6], 0, [0.5, 0.75]; yref="paper") + plot([trace1], Layout(;shapes=shapes)) +end + +function vlines5() + # we can also set arbitrary line attributes line color and dash + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = vline([2, 6], 0, [0.5, 0.75]; yref="paper", + line_color="green", line_dash="dashdot") + plot([trace1], Layout(;shapes=shapes)) +end + +function hlines1() + # one scalar argument produces one line. Need to wrap in an array because + # layout.shapes should be an array + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = [hline(2)] + plot([trace1], Layout(;shapes=shapes)) +end + +function hlines2() + # one argument draws a horizontal line across the entire plot + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = hline([25, 81]) + plot([trace1], Layout(;shapes=shapes)) +end + +function hlines3() + # xref paper makes the 2nd and 3rd arguments on a (0, 1) scale horizontally + # so 0.5 is 1/2 through the plot regardless of the values on x-axis + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = hline([25, 81], 0, 0.5; xref="paper") + plot([trace1], Layout(;shapes=shapes)) +end + +function hlines4() + # Whichever argument is a scalar is repeated + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = hline([25, 81], 0, [0.5, 0.75]; xref="paper") + plot([trace1], Layout(;shapes=shapes)) +end + +function hlines5() + # we can also set arbitrary line attributes line color and dash + trace1 = scatter(;x=1:10, y=(1:10).^2) + shapes = hline([25, 81], 0, [0.5, 0.75]; xref="paper", + line_color="green", line_dash="dashdot") + plot([trace1], Layout(;shapes=shapes)) +end diff --git a/PlotlyJS/examples/subplots.jl b/PlotlyJS/examples/subplots.jl new file mode 100644 index 0000000..3d11594 --- /dev/null +++ b/PlotlyJS/examples/subplots.jl @@ -0,0 +1,138 @@ +include("line_scatter.jl") + +function subplots1() + p1 = linescatter1() + p2 = linescatter2() + p = [p1 p2] + p +end + +function subplots2() + p1 = linescatter1() + p2 = linescatter2() + p = [p1; p2] + p +end + + +function subplots3() + p1 = linescatter6() + p2 = linescatter2() + p3 = linescatter3() + p4 = batman() + p = [p1 p2; p3 p4] + p.plot.layout["showlegend"] = false + p.plot.layout["width"] = 1000 + p.plot.layout["height"] = 600 + p +end + + +function subplots_withcomprehension() + hcat([plot(scatter(x=1:5, y=rand(5))) for i in 1:3]...) +end + + +function subplots_withsharedaxes() + data = [ + scatter(x=1:3, y=2:4), + scatter(x=20:10:40, y=fill(5, 3), xaxis="x2", yaxis="y"), + scatter(x=2:4, y=600:100:800, xaxis="x", yaxis="y3"), + scatter(x=4000:1000:6000, y=7000:1000:9000, xaxis="x4", yaxis="y4") + ] + layout = Layout( + xaxis_domain=[0, 0.45], + yaxis_domain=[0, 0.45], + xaxis4=attr(domain=[0.55, 1.0], anchor="y4"), + xaxis2_domain=[0.55, 1], + yaxis3_domain=[0.55, 1], + yaxis4=attr(domain=[0.55, 1], anchor="x4") + ) + plot(data, layout) +end + +function with_make_subplots1() + + # The `shared_xaxes` argument to `make_subplots` can be used to link the x + # axes of subplots in the resulting figure. The `vertical_spacing` argument + # is used to control the vertical spacing between rows in the subplot grid. + + # Here is an example that creates a figure with 3 vertically stacked + # subplots with linked x axes. A small vertical spacing value is used to + # reduce the spacing between subplot rows. + + p = make_subplots(rows=3, cols=1, shared_xaxes=true, vertical_spacing=0.02) + add_trace!(p, scatter(x=0:2, y=10:12), row=3, col=1) + add_trace!(p, scatter(x=2:4, y=100:10:120), row=2, col=1) + add_trace!(p, scatter(x=3:5, y=1000:100:1200), row=1, col=1) + relayout!(p, title_text="Stacked Subplots with Shared X-Axes") + p +end + +function with_make_subplots2() + # The `shared_yaxes` argument to `make_subplots` can be used to link the y + # axes of subplots in the resulting figure. + + # Here is an example that creates a figure with a 2 x 2 subplot grid, where + # the y axes of each row are linked. + + p = make_subplots(rows=3, cols=2, shared_yaxes=true) + add_trace!(p, scatter(x=0:2, y=10:12), row=1, col=1) + add_trace!(p, scatter(x=20:10:40, y=1:3), row=1, col=2) + add_trace!(p, scatter(x=3:5, y=600:100:800), row=2, col=1) + add_trace!(p, scatter(x=3:5, y=1000:100:1200), row=2, col=2) + relayout!(p, title_text="Multiple Subplots with Shared Y-Axes") + p +end + +function with_make_subplots3() + # The `specs` argument to `make_subplots` is used to configure per-subplot + # options. `specs` must be a `Matrix` with dimensions that match those + # provided as the `rows` and `cols` arguments. The elements of `specs` may + # either be `missing`, indicating no subplot should be initialized starting + # with this grid cell, or an instance of `Spec` containing subplot options. + # The `colspan` subplot option specifies the number of grid columns that the + # subplot starting in the given cell should occupy. If unspecified, + # `colspan` defaults to 1. + + # Here is an example that creates a 2 by 2 subplot grid containing 3 + # subplots. The subplot `specs` element for position (2, 1) has a `colspan` + # value of 2, causing it to span the full figure width. The subplot `specs` + # element f or position (2, 2) is `None` because no subplot begins at this + # location in the grid. + p = make_subplots( + rows=2, cols=2, + specs=[Spec() Spec(); Spec(colspan=2) missing], + subplot_titles=["First Subplot" "Second Subplot"; "Third Subplot" missing] + ) + + add_trace!(p, scatter(x=[1, 2], y=[1, 2]), row=1, col=1) + add_trace!(p, scatter(x=[1, 2], y=[1, 2]), row=1, col=2) + add_trace!(p, scatter(x=[1, 2, 3], y=[2, 1, 2]), row=2, col=1) + + relayout!(p, showlegend=false, title_text="Specs with Subplot Title") + p +end + +function with_make_subplots4() + # Here is an example that uses the `rowspan` and `colspan` subplot options + # to create a custom subplot layout with subplots of mixed sizes. + p = make_subplots( + rows=5, cols=2, + specs=[Spec() Spec(rowspan=2) + Spec() missing + Spec(rowspan=2, colspan=2) missing + missing missing + Spec() Spec()] + ) + + add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(1,1)"), row=1, col=1) + add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(1,2)"), row=1, col=2) + add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(2,1)"), row=2, col=1) + add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(3,1)"), row=3, col=1) + add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(5,1)"), row=5, col=1) + add_trace!(p, scatter(x=[1, 2], y=[1, 2], name="(5,2)"), row=5, col=2) + + relayout!(p, height=600, width=600, title_text="specs examples") + p +end diff --git a/PlotlyJS/examples/tables.jl b/PlotlyJS/examples/tables.jl new file mode 100644 index 0000000..4dda39f --- /dev/null +++ b/PlotlyJS/examples/tables.jl @@ -0,0 +1,98 @@ +using PlotlyJS, DataFrames, CSV, HTTP + +function table1() + values = [ + "Salaries" 1200000 1300000 1300000 1400000 + "Office" 20000 20000 20000 20000 + "Merchandise" 80000 70000 120000 90000 + "Legal" 2000 2000 2000 2000 + "TOTAL" 12120000 130902000 131222000 14102000 + ] + + trace = table( + header=attr( + values=["Expenses", "Q1", "Q2", "Q3", "Q4"], + align="center", line=attr(width=1, color="black"), + fill_color="grey", font=attr(family="Arial", size=12, color="white") + ), + cells=attr( + values=values, align="center", line=attr(color="black", width=1), + font=attr(family="Arial", size=11, color="black") + ) + ) + plot(trace) + +end + +function table2() + values = [ + "Salaries" 1200000 1300000 1300000 1400000 + "Office" 20000 20000 20000 20000 + "Merchandise" 80000 70000 120000 90000 + "Legal" 2000 2000 2000 2000 + "TOTAL" 12120000 130902000 131222000 14102000 + ] + + trace = table( + header=attr( + values=["EXPENSES", "Q1", "Q2", "Q3", "Q4"], + align=["left", "center"], line=attr(width=1, color="#506784"), + fill_color="#119DFF", + font=attr(family="Arial", size=12, color="white") + ), + cells=attr( + values=values, align=["left", "center"], + line=attr(color="#506784", width=1), + font=attr(family="Arial", size=11, color="#506784"), + fill_color=["#25FEFD", "white"] + ) + ) + plot(trace) + +end + + +function table2a() + p1 = table1() + restyle!(p1, + header=attr( + align=["left", "center"], line_color="#506784", fill_color="#119DFF" + ), + cells=attr( + align=["left", "center"], line_color="#506784", + fill_color=["#25FEFD", "white"], font_color="#506784" + ) + ) + p1 +end + + +function table3() + url = "https://raw.githubusercontent.com/plotly/datasets/master/Mining-BTC-180.csv" + df = DataFrame(CSV.File(HTTP.get(url).body)) + + trace = table( + columnwidth=[200, 500, 600, 600, 400, 400, 600, 600, 600], + # columnorder=0:9, + header=attr( + values=map(x -> replace(string(x), '_' => '-'), names(df)), + align="center", + line=attr(width=1, color="rgb(50, 50, 50)"), + fill_color=["rgb(235, 100, 230)"], + font=attr(family="Arial", size=12, color="white") + ), + cells=attr( + values=Array(df), + align=["center", "center"], + line=attr(width=1, color="black"), + fill_color=["rgba(228, 222, 249, 0.65)", "rgb(235, 193, 238)", "rgba(228, 222, 249, 0.65)"], + font=attr(family="Arial", size=10, color="black") + ) + ) + + layout = Layout( + title="Bitcoin mining stats for 180 days", + width=1200 + ) + plot(trace, layout) +end diff --git a/PlotlyJS/examples/ternary.jl b/PlotlyJS/examples/ternary.jl new file mode 100644 index 0000000..2012dae --- /dev/null +++ b/PlotlyJS/examples/ternary.jl @@ -0,0 +1,107 @@ +using PlotlyJS, JSON + +function ternary_markers() + function make_ax(title, tickangle) + attr(title=title, titlefont_size=20, tickangle=tickangle, + tickfont_size=15, tickcolor="rgba(0, 0, 0, 0)", ticklen=5, + showline=true, showgrid=true) + end + + raw_data = [ + Dict(:journalist=>75, :developer=>:25, :designer=>0, :label=>"point 1"), + Dict(:journalist=>70, :developer=>:10, :designer=>20, :label=>"point 2"), + Dict(:journalist=>75, :developer=>:20, :designer=>5, :label=>"point 3"), + Dict(:journalist=>5, :developer=>:60, :designer=>35, :label=>"point 4"), + Dict(:journalist=>10, :developer=>:80, :designer=>10, :label=>"point 5"), + Dict(:journalist=>10, :developer=>:90, :designer=>0, :label=>"point 6"), + Dict(:journalist=>20, :developer=>:70, :designer=>10, :label=>"point 7"), + Dict(:journalist=>10, :developer=>:20, :designer=>70, :label=>"point 8"), + Dict(:journalist=>15, :developer=>:5, :designer=>80, :label=>"point 9"), + Dict(:journalist=>10, :developer=>:10, :designer=>80, :label=>"point 10"), + Dict(:journalist=>20, :developer=>:10, :designer=>70, :label=>"point 11") + ] + + t = scatterternary( + mode="markers", + a=[_x[:journalist] for _x in raw_data], + b=[_x[:developer] for _x in raw_data], + c=[_x[:designer] for _x in raw_data], + text=[_x[:label] for _x in raw_data], + marker=attr(symbol=100, color="#DB7365", size=14, line_width=2) + ) + layout = Layout( + ternary=attr( + sum=100, + aaxis=make_ax("Journalist", 0), + baxis=make_ax("Developer", 45), + caxis=make_ax("Designer", -45), + bgcolor="#fff1e0", + ), annotations=attr( + showarrow=false, + text="Replica of Tom Pearson's block", + x=1.0, y=1.3, font_size=15 + ), + paper_bgcolor="#fff1e0" + ) + plot(t, layout) +end + +function filled_ternary() + function make_ax(title) + attr( + title=title, + ticksuffix="%", + min=0.01, + linewidth=2, + ticks="outside", + ticklen=8, + showgrid=true + ) + end + + fn = tempname() + download("https://gist.githubusercontent.com/davenquinn/988167471993bc2ece29/raw/f38d9cb3dd86e315e237fde5d65e185c39c931c2/data.json", fn) + raw_data = JSON.parsefile(fn) + rm(fn) + + colors = [ + "#8dd3c7", + "#ffffb3", + "#bebada", + "#fb8072", + "#80b1d3", + "#fdb462", + "#b3de69", + "#fccde5", + "#d9d9d9", + "#bc80bd", + "#ccebc5", + "#ffed6f" + ] + + traces = Array{GenericTrace,1}(undef, length(raw_data)) + for (i, (k, v)) in enumerate(raw_data) + traces[i] = scatterternary(mode="lines", name=k, + a=[_x["clay"] for _x in v], + b=[_x["sand"] for _x in v], + c=[_x["silt"] for _x in v], + line_color="#444", + fill="toself", + fillcolor=colors[i], + hoveron="fills+points" + ) + end + layout = Layout( + ternary=attr( + sum=100, + aaxis=make_ax("Clay"), + baxis=make_ax("Sand"), + caxis=make_ax("Slit")), + showlegend=false, + width=700, + annotations=[attr( + showarrow=false, x=0.15, y=1.1, text="Soil types fill plot" + )] + ) + plot(traces, layout) +end diff --git a/PlotlyJS/examples/time_series.jl b/PlotlyJS/examples/time_series.jl new file mode 100644 index 0000000..428aace --- /dev/null +++ b/PlotlyJS/examples/time_series.jl @@ -0,0 +1,6 @@ +using PlotlyJS + +function datetimestrings() + x = ["2013-10-04 22:23:00", "2013-11-04 22:23:00", "2013-12-04 22:23:00"] + plot(scatter(x=x, y=[1 ,3, 6])) +end diff --git a/PlotlyJS/examples/violin.jl b/PlotlyJS/examples/violin.jl new file mode 100644 index 0000000..6569a35 --- /dev/null +++ b/PlotlyJS/examples/violin.jl @@ -0,0 +1,144 @@ +using PlotlyJS, RDatasets, DataFrames + + +function violin_box_overlay() + y = abs.(100 .* randn(300)) + data = [ + violin(x0="sample 1", name="violin", y=y, points="all"), + box(x0="sample 1", name="box", y=y, boxpoints=false) + ] + plot(data, Layout(legend=attr(x=0.95, xanchor="right"))) +end + + +function violin_grouped() + days = repeat(["day 1", "day 2"], inner=5) + y_kale = [0.2, 0.2, 0.6, 1, 0.5, 0.4, 0.2, 0.7, 0.9, 0.1, 0.5, 0.3] + y_radish = [0.6, 0.7, 0.3, 0.6, 0, 0.5, 0.7, 0.9, 0.5, 0.8, 0.7, 0.2] + y_carrot = [0.1, 0.3, 0.1, 0.9, 0.6, 0.6, 0.9, 1, 0.3, 0.6, 0.8, 0.5] + colors = ["#3D9970", "#FF4136", "#FF851B"] + names = ["kale", "radishes", "carrots"] + ys = (y_kale, y_radish, y_carrot) + + data = [ + violin( + y=y, name=name, x=days, span=[0, nothing], jitter=0, points="all", + marker=attr(symbol="line-ew", color=color, line=attr(color=color, width=2)) + ) for (y, name, color) in zip(ys, names, colors) + ] + layout = Layout( + yaxis=attr(zeroline=false, title="normalized moisture"), + violinmode="group" + ) + plot(data, layout) +end + + +function violin_nonlinear() + p1 = plot( + violin( + x=["1798-01-01", "1798-04-04", "1798-05-05", + "1798-05-05", "1798-07-05", "1798-07-22", "1799-01-01"], + orientation="h", box_visible=true, xcalendar="discworld", + name="discworld dates" + ) + ) + p2 = plot( + violin( + x=["A", "B", "C", "C", "C", "D", "G"], + orientation="h", box_visible=true, xcalendar="discworld", + name="categories" + ), Layout(xaxis_categoryarray='A':'G') + ) + p = [p1; p2] + relayout!(p, showlegend=false, margin_l=100) + p +end + + +function violin_old_faithful() + y = [79, 54, 74, 62, 85, 55, 88, 85, 51, 85, 54, 84, 78, 47, 83, 52, 62, + 84, 52, 79, 51, 47, 78, 69, 74, 83, 55, 76, 78, 79, 73, 77, 66, 80, 74, 52, + 48, 80, 59, 90, 80, 58, 84, 58, 73, 83, 64, 53, 82, 59, 75, 90, 54, 80, 54, + 83, 71, 64, 77, 81, 59, 84, 48, 82, 60, 92, 78, 78, 65, 73, 82, 56, 79, 71, + 62, 76, 60, 78, 76, 83, 75, 82, 70, 65, 73, 88, 76, 80, 48, 86, 60, 90, 50, + 78, 63, 72, 84, 75, 51, 82, 62, 88, 49, 83, 81, 47, 84, 52, 86, 81, 75, 59, + 89, 79, 59, 81, 50, 85, 59, 87, 53, 69, 77, 56, 88, 81, 45, 82, 55, 90, 45, + 83, 56, 89, 46, 82, 51, 86, 53, 79, 81, 60, 82, 77, 76, 59, 80, 49, 96, 53, + 77, 77, 65, 81, 71, 70, 81, 93, 53, 89, 45, 86, 58, 78, 66, 76, 63, 88, 52, + 93, 49, 57, 77, 68, 81, 81, 73, 50, 85, 74, 55, 77, 83, 83, 51, 78, 84, 46, + 83, 55, 81, 57, 76, 84, 77, 81, 87, 77, 51, 78, 60, 82, 91, 53, 78, 46, 77, + 84, 49, 83, 71, 80, 49, 75, 64, 76, 53, 94, 55, 76, 50, 82, 54, 75, 78, 79, + 78, 78, 70, 79, 70, 54, 86, 50, 90, 54, 54, 77, 79, 64, 75, 47, 86, 63, 85, + 82, 57, 82, 67, 74, 54, 83, 73, 73, 88, 80, 71, 83, 56, 79, 78, 84, 58, 83, + 43, 60, 75, 81, 46, 90, 46, 74] + plot(violin(y=y, points="all", name="Old Faithful", meanline_visible=true)) +end + + +function violin_side_by_side() + # requires RDatasets and DataFrames + tips = RDatasets.dataset("reshape2", "tips") + parts = zip( + ("Female", "Male"), + ("positive", "negative"), + ("#bebada", "#8dd3c7"), + (1.0, -0.6) + ) + traces = GenericTrace[] + for (sex, side, color, pointpos) in parts + sub_tips = tips[tips[!, :Sex] .== sex, :] + sub_traces = violin(sub_tips, + group=:Day, + x=:TotalBill, y0=(df) -> df[1, :Day], + side=side, orientation="h", + marker=attr(line=attr(width=2, color=color), symbol="line-ns"), + line_color=color, + hoveron="points+kde", text=(df) -> "Sample length $(size(df, 1))", + scalemode="count", scalegroup=sex, legendgroup=sex, name=sex, + points="all", jitter=0, pointpos=pointpos, + span=[0], + box_visible=true, meanline_visible=true, + showlegend=false, + ) + sub_traces[1][:showlegend] = true + append!(traces, sub_traces) + end + # TODO: make the layout + layout = Layout( + hovermode="closest", violinmode="overlay", + title="Total bill distribution
scaled by number of bills per gender", + legend_tracegroupgap=0, violingap=0, violingroupgap=0, + yaxis=attr(showgrid=true, categoryarray=["Thur", "Fri", "Sat", "Sun"]), + ) + plot(traces, layout) +end + +function violin_style() + y1 = vcat(abs.(20 .* rand(100)), rand(UInt16, 300) .* 500 ./ typemax(UInt16)) + y2 = [25.261999999999997, 66.5419, 98.2114, 0.09070629 ] + box = attr(fillcolor="black", line_color="black", width=0.01) + span = [0, nothing] + trace1 = violin( + bandwidth=5, points=false, y=y1, name="Radial Velocity", + span=span, line_color="#67353E", box=box + ) + trace2 = violin( + bandwidth=5, points=false, y=y2, name="Pulsar Timing", + span=span, line_color="#34ABA2", box=box + ) + + layout = Layout( + paper_bgcolor="#d3d3d3", plot_bgcolor="#d3d3d3", + showlegend=false, violingap=0, xaxis_side="top", + yaxis=attr( + showline=false, showticklabels=false, range=(-5, 550), + zeroline=false, visible=false, showgrid=false, + ), + annotations=[attr( + text="Orbital Period Estimations", font_size=20, + xref="paper", yref="paper", showarrow=false, + )] + ) + plot([trace1, trace2], layout) +end diff --git a/PlotlyJS/src/PlotlyJS.jl b/PlotlyJS/src/PlotlyJS.jl new file mode 100644 index 0000000..6e25e6c --- /dev/null +++ b/PlotlyJS/src/PlotlyJS.jl @@ -0,0 +1,194 @@ +module PlotlyJS + +using Base64 +using Reexport +@reexport using PlotlyBase +using JSON +using REPL, Pkg, Pkg.Artifacts, DelimitedFiles # stdlib + +# need to import some functions because methods are meta-generated +import PlotlyBase: + restyle!, relayout!, update!, addtraces!, deletetraces!, movetraces!, + redraw!, extendtraces!, prependtraces!, purge!, to_image, download_image, + restyle, relayout, update, addtraces, deletetraces, movetraces, redraw, + extendtraces, prependtraces, prep_kwargs, sizes, _tovec, + react, react!, add_trace! + +using WebIO +using JSExpr +using JSExpr: @var, @new +using Blink +using Pkg.Artifacts +using Requires + +export plot, dataset, list_datasets, make_subplots, savefig, mgrid + +# globals for this package +const _pkg_root = dirname(dirname(@__FILE__)) +const _js_path = joinpath(artifact"plotly-artifacts", "plotly.min.js") +const _js_cdn_path = "https://cdn.plot.ly/plotly-latest.min.js" +const _mathjax_cdn_path = + "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_SVG" + +struct PlotlyJSDisplay <: AbstractDisplay end + +# include the rest of the core parts of the package +include("display.jl") +include("util.jl") +include("kaleido.jl") + +make_subplots(;kwargs...) = plot(Layout(Subplots(;kwargs...))) + +@doc (@doc Subplots) make_subplots + +function docs() + schema_path = joinpath(dirname(dirname(@__FILE__)), "deps", "schema.html") + if !isfile(schema_path) + msg = "schema docs not built. Run `Pkg.build(\"PlotlyJS\")` to generate" + error(msg) + end + w = Blink.Window() + wait(w.content) + Blink.content!(w, "html", open(f -> read(f, String), schema_path), fade=false, async=false) +end + + +@enum RENDERERS BLINK IJULIA BROWSER DOCS + +const DEFAULT_RENDERER = Ref(BLINK) + +function set_default_renderer(s::RENDERERS) + global DEFAULT_RENDERER + DEFAULT_RENDERER[] = s +end + +@inline get_renderer() = DEFAULT_RENDERER[] + +list_datasets() = readdir(joinpath(artifact"plotly-artifacts", "datasets")) +function check_dataset_exists(name::String) + ds = list_datasets() + name_ext = Dict(name => strip(ext, '.') for (name, ext) in splitext.(ds)) + if !haskey(name_ext, name) + error("Unknown dataset $name, known datasets are $(collect(keys(name_ext)))") + end + ds_path = joinpath(artifact"plotly-artifacts", "datasets", "$(name).$(name_ext[name])") + return ds_path +end + +function dataset(name::String)::Dict{String,Any} + ds_path = check_dataset_exists(name) + if endswith(ds_path, "csv") + # if csv, use DelimitedFiles and convert to dict + data = DelimitedFiles.readdlm(ds_path, ',') + return Dict(zip(data[1, :], data[2:end, i] for i in 1:size(data, 2))) + elseif endswith(ds_path, "json") + # use json + return JSON.parsefile(ds_path) + end + error("should not ever get here!!! Please file an issue") +end + + +function __init__() + _build_log = joinpath(_pkg_root, "deps", "build.log") + if isfile(_build_log) && occursin("Warning:", read(_build_log, String)) + @warn("Warnings were generated during the last build of PlotlyJS: please check the build log at $_build_log") + end + + kaleido_task = Base.Threads.@spawn _start_kaleido_process() + + if !isfile(_js_path) + @info("plotly.js javascript libary not found -- downloading now") + include(joinpath(_pkg_root, "deps", "build.jl")) + end + + # set default renderer + # First check env var + env_val = get(ENV, "PLOTLY_RENDERER_JULIA", missing) + if !ismissing(env_val) + env_symbol = Symbol(uppercase(env_val)) + options = Dict(v => k for (k, v) in collect(Base.Enums.namemap(PlotlyJS.RENDERERS))) + renderer_int = get(options, env_symbol, missing) + if ismissing(renderer_int) + @warn "Unknown value for env var `PLOTLY_RENDERER_JULIA` \"$(env_val)\", known options are $(string.(keys(options)))" + else + set_default_renderer(RENDERERS(renderer_int)) + end + else + # we have no env-var + # check IJULIA + isdefined(Main, :IJulia) && Main.IJulia.inited && set_default_renderer(IJULIA) + end + + # set up display + insert!(Base.Multimedia.displays, findlast(x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotlyJSDisplay()) + + atreplinit(i -> begin + while PlotlyJSDisplay() in Base.Multimedia.displays + popdisplay(PlotlyJSDisplay()) + end + insert!(Base.Multimedia.displays, findlast(x -> x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotlyJSDisplay()) + end) + + @require JSON2 = "2535ab7d-5cd8-5a07-80ac-9b1792aadce3" JSON2.write(io::IO, p::SyncPlot) = JSON2.write(io, p.plot) + @require JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" begin + JSON3.write(io::IO, p::SyncPlot) = JSON.print(io, p.plot) + JSON3.write(p::SyncPlot) = JSON.json(p.plot) + end + + @require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin + + function IJulia.display_dict(p::SyncPlot) + Dict( + "application/vnd.plotly.v1+json" => JSON.lower(p), + "text/plain" => sprint(show, "text/plain", p), + "text/html" => let + buf = IOBuffer() + show(buf, MIME("text/html"), p) + String(resize!(buf.data, buf.size)) + end + ) + end + end + + @require CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" begin + function dataset(::Type{CSV.File}, name::String) + ds_path = check_dataset_exists(name) + if !endswith(ds_path, "csv") + error("Can only construct CSV.File from a csv data source") + end + CSV.File(ds_path) + end + @require DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" begin + dataset(::Type{DataFrames.DataFrame}, name::String) = DataFrames.DataFrame(dataset(CSV.File, name)) + end + end + + wait(kaleido_task) + + if ccall(:jl_generating_output, Cint, ()) == 1 + # ensure precompilation of packages depending on PlotlyJS finishes + if isdefined(P, :proc) + close(P.stdin) + wait(P.proc) + end + end +end + +# for methods that update the layout, first apply to the plot, then let plotly.js +# deal with the rest via the react function +for (k, v) in vcat(PlotlyBase._layout_obj_updaters, PlotlyBase._layout_vector_updaters) + @eval function PlotlyBase.$(k)(p::SyncPlot, args...;kwargs...) + $(k)(p.plot, args...; kwargs...) + send_command(p.scope, :react, p.plot.data, p.plot.layout) + end +end + +for k in [:add_hrect!, :add_hline!, :add_vrect!, :add_vline!, :add_shape!, :add_layout_image!] + @eval function PlotlyBase.$(k)(p::SyncPlot, args...;kwargs...) + $(k)(p.plot, args...; kwargs...) + send_command(p.scope, :react, p.plot.data, p.plot.layout) + end +end + +end # module diff --git a/PlotlyJS/src/display.jl b/PlotlyJS/src/display.jl new file mode 100644 index 0000000..ba1c50a --- /dev/null +++ b/PlotlyJS/src/display.jl @@ -0,0 +1,353 @@ +# ----------------------------------------- # +# SyncPlot -- sync Plot object with display # +# ----------------------------------------- # +mutable struct SyncPlot + plot::PlotlyBase.Plot + scope::Scope + window::Union{Nothing,Blink.Window} +end + +Base.getindex(p::SyncPlot, key) = p.scope[key] # look up Observables + +@WebIO.register_renderable(SyncPlot) do plot + return WebIO.render(plot.scope) +end + +function Base.show(io::IO, mm::MIME"text/html", p::SyncPlot) + # if we are rendering docs -- short circuit and display html + if get_renderer() == DOCS + return show(io, mm, p.plot, full_html=false, include_plotlyjs="require-loaded", include_mathjax=missing) + end + show(io, mm, p.scope) +end +Base.show(io::IO, mm::MIME"application/prs.juno.plotpane+html", p::SyncPlot) = show(io, mm, p.scope) + +function SyncPlot( + p::Plot; + kwargs... + ) + lowered = JSON.lower(p) + id = string("#plot-", p.divid) + + # setup scope + deps = [ + "Plotly" => joinpath(artifact"plotly-artifacts", "plotly.min.js"), + joinpath(@__DIR__, "..", "assets", "plotly_webio.bundle.js") + ] + scope = Scope(imports=deps) + scope.dom = dom"div"(id=string("plot-", p.divid)) + + # INPUT: Observables for plot events + scope["hover"] = Observable(Dict()) + scope["selected"] = Observable(Dict()) + scope["click"] = Observable(Dict()) + scope["relayout"] = Observable(Dict()) + scope["image"] = Observable("") + scope["__gd_contents"] = Observable{Any}(Dict()) # for testing + + # OUTPUT: setup an observable which sends modify commands + scope["_commands"] = Observable{Any}([]) + scope["_toImage"] = Observable(Dict()) + scope["_downloadImage"] = Observable(Dict()) + scope["__get_gd_contents"] = Observable("") + + onjs(scope["_toImage"], @js function (options) + this.Plotly.toImage(this.plotElem, options).then(function (data) + $(scope["image"])[] = data + end) + end) + + onjs(scope["__get_gd_contents"], @js function (prop) + if prop == "data" + $(scope["__gd_contents"])[] = this.plotElem.data + end + + if prop == "layout" + $(scope["__gd_contents"])[] = this.plotElem.layout + end + end) + + onjs(scope["_downloadImage"], @js function (options) + this.Plotly.downloadImage(this.plotElem, options) + end) + + # Do the respective action when _commands is triggered + onjs(scope["_commands"], @js function (args) + @var fn = args.shift() + @var elem = this.plotElem + @var Plotly = this.Plotly + args.unshift(elem) # use div as first argument + Plotly[fn].apply(this, args) + end) + + onimport(scope, JSExpr.@js function (Plotly, PlotlyWebIO) + # Add the PlotlyCommands object to the WebIO JS instance + PlotlyWebIO.init(WebIO) + + # set up container element + @var gd = this.dom.querySelector($id); + + # save some vars for later + this.plotElem = gd + this.Plotly = Plotly + if (window.Blink !== undefined) + # set css style for auto-resize + gd.style.width = "100%"; + gd.style.height = "100vh"; + gd.style.marginLeft = "0%"; + gd.style.marginTop = "0vh"; + end + + window.onresize = () -> Plotly.Plots.resize(gd) + + # Draw plot in container + Plotly.newPlot( + gd, + $(lowered[:data]), + $(lowered[:layout]), + $(lowered[:config]), + ) + + # hook into plotly events + gd.on("plotly_hover", function (data) + @var filtered_data = WebIO.PlotlyCommands.filterEventData(gd, data, "hover"); + if !(filtered_data.isnil) + $(scope["hover"])[] = filtered_data.out + end + end) + + gd.on("plotly_unhover", () -> $(scope["hover"])[] = Dict()) + + gd.on("plotly_selected", function (data) + @var filtered_data = WebIO.PlotlyCommands.filterEventData(gd, data, "selected"); + if !(filtered_data.isnil) + $(scope["selected"])[] = filtered_data.out + end + end) + + gd.on("plotly_deselect", () -> $(scope["selected"])[] = Dict()) + + gd.on("plotly_relayout", function (data) + @var filtered_data = WebIO.PlotlyCommands.filterEventData(gd, data, "relayout"); + if !(filtered_data.isnil) + $(scope["relayout"])[] = filtered_data.out + end + end) + + gd.on("plotly_click", function (data) + @var filtered_data = WebIO.PlotlyCommands.filterEventData(gd, data, "click"); + if !(filtered_data.isnil) + $(scope["click"])[] = filtered_data.out + end + end) + end) + + # create no-op `on` callback for image so it is _always_ sent + # to us + on(scope["image"]) do x end + + SyncPlot(p, scope, nothing) +end + +function plot(args...; kwargs...) + SyncPlot(Plot(args...; kwargs...)) +end + +# Add some basic Julia API methods on SyncPlot that just forward onto the Plot +Base.size(sp::SyncPlot) = size(sp.plot) +Base.copy(sp::SyncPlot) = SyncPlot(copy(sp.plot)) + +Base.display(::PlotlyJSDisplay, p::SyncPlot) = display_blink(p::SyncPlot) + +function display_blink(p::SyncPlot) + sizeBuffer = 1.15 + plotSize = size(p.plot) + windowOptions = Dict( + "width" => floor(Int, plotSize[1] * sizeBuffer), + "height" => floor(Int, plotSize[2] * sizeBuffer) + ) + p.window = Blink.Window(windowOptions) + Blink.body!(p.window, p.scope) +end + +function Base.close(p::SyncPlot) + if p.window !== nothing && Blink.active(p.window) + close(p.window) + end +end + +function send_command(scope, cmd, args...) + # The handler for _commands is set up when plot is constructed + scope["_commands"][] = [cmd, args...] + nothing +end + +function add_trace!(p::SyncPlot, trace::GenericTrace; kw...) + add_trace!(p.plot, trace; kw...) + send_command(p.scope, :react, p.plot.data, p.plot.layout) +end + + +# ----------------------- # +# Plotly.js api functions # +# ----------------------- # + +# for each of these we first update the Julia object, then update the display + +function restyle!( + plt::SyncPlot, ind::Union{Int,AbstractVector{Int}}, + update::AbstractDict=Dict(); + kwargs... + ) + restyle!(plt.plot, ind, update; kwargs...) + send_command(plt.scope, :restyle, merge(update, prep_kwargs(kwargs)), ind .- 1) +end + +function restyle!(plt::SyncPlot, update::AbstractDict=Dict(); kwargs...) + restyle!(plt.plot, update; kwargs...) + send_command(plt.scope, :restyle, merge(update, prep_kwargs(kwargs))) +end + +function relayout!(plt::SyncPlot, update::AbstractDict=Dict(); kwargs...) + relayout!(plt.plot, update; kwargs...) + update!(plt, layout=plt.plot.layout) +end + +function react!(plt::SyncPlot, data::AbstractVector{<:AbstractTrace}, layout::Layout) + react!(plt.plot, data, layout) + send_command(plt.scope, :react, data, layout) +end + +function update!( + plt::SyncPlot, ind::Union{Int,AbstractVector{Int}}, + update::AbstractDict=Dict(); + layout::Layout=Layout(), + kwargs...) + update!(plt.plot, ind, update; layout=layout, kwargs...) + send_command(plt.scope, :update, merge(update, prep_kwargs(kwargs)), layout, ind .- 1) +end + +function update!( + plt::SyncPlot, update::AbstractDict=Dict(); layout::Layout=Layout(), + kwargs... + ) + update!(plt.plot, update; layout=layout, kwargs...) + send_command(plt.scope, :update, merge(update, prep_kwargs(kwargs)), layout) +end + +function addtraces!(plt::SyncPlot, traces::AbstractTrace...) + addtraces!(plt.plot, traces...) + send_command(plt.scope, :addTraces, traces) +end + +function addtraces!(plt::SyncPlot, i::Int, traces::AbstractTrace...) + addtraces!(plt.plot, i, traces...) + send_command(plt.scope, :addTraces, traces, i - 1) +end + +function deletetraces!(plt::SyncPlot, inds::Int...) + deletetraces!(plt.plot, inds...) + send_command(plt.scope, :deleteTraces, collect(inds) .- 1) +end + +function movetraces!(plt::SyncPlot, to_end::Int...) + movetraces!(plt.plot, to_end...) + send_command(plt.scope, :moveTraces, traces, collect(to_end) .- 1) +end + +function movetraces!( + plt::SyncPlot, src::AbstractVector{Int}, dest::AbstractVector{Int} + ) + movetraces!(plt.plot, src, dest) + send_command(plt.scope, :moveTraces, src .- 1, dest .- 1) +end + +function redraw!(plt::SyncPlot) + redraw!(plt.plot) + send_command(plt.scope, :redraw) +end + +function purge!(plt::SyncPlot) + purge!(plt.plot) + send_command(plt.scope, :purge) +end + +function to_image(plt::SyncPlot; kwargs...) + to_image(plt.plot) + plt.scope["image"][] = "" # reset + plt.scope["_toImage"][] = Dict(kwargs) + + tries = 0 + while length(plt.scope["image"][]) == 0 + tries == 10 && error("Could not get image") + sleep(0.25) + tries += 1 + end + return plt["image"].val +end + +function download_image(plt::SyncPlot; kwargs...) + download_image(plt.plot) + plt.scope["_downloadImage"][] = Dict(kwargs) + nothing +end + +# unexported (by plotly.js) api methods +function extendtraces!(plt::SyncPlot, update::AbstractDict, + indices::AbstractVector{Int}=[1], maxpoints=-1;) + extendtraces!(plt.plot, update, indices, maxpoints) + send_command( + plt.scope, :extendTraces, prep_kwargs(update), indices .- 1, maxpoints + ) +end + +function prependtraces!(plt::SyncPlot, update::AbstractDict, + indices::AbstractVector{Int}=[1], maxpoints=-1;) + prependtraces!(plt.plot, update, indices, maxpoints) + send_command( + plt.scope, :prependTraces, prep_kwargs(update), indices .- 1, maxpoints + ) +end + +for f in [:restyle, :relayout, :update, :addtraces, :deletetraces, + :movetraces, :redraw, :extendtraces, :prependtraces, :purge, :react] + f! = Symbol(f, "!") + @eval function $(f)(plt::SyncPlot, args...; kwargs...) + out = SyncPlot(deepcopy(plt.plot)) + $(f!)(out, args...; kwargs...) + out + end +end + +# add extra same extra methods we have on ::Plot for these functions +for f in (:extendtraces!, :prependtraces!) + @eval begin + function $(f)(p::SyncPlot, inds::Vector{Int}=[0], + maxpoints=-1; update...) + d = Dict() + for (k, v) in update + d[k] = _tovec(v) + end + ($f)(p, d, inds, maxpoints) + end + + function $(f)(p::SyncPlot, ind::Int, maxpoints=-1; + update...) + ($f)(p, [ind], maxpoints; update...) + end + + function $(f)(p::SyncPlot, update::AbstractDict, ind::Int, + maxpoints=-1) + ($f)(p, update, [ind], maxpoints) + end + end +end + + +for mime in ["text/plain", "application/vnd.plotly.v1+json", "application/prs.juno.plotpane+html"] + function Base.show(io::IO, m::MIME{Symbol(mime)}, p::SyncPlot, args...) + show(io, m, p.plot, args...) + end +end + +PlotlyBase.savejson(sp::SyncPlot, fn::String) = PlotlyBase.savejson(sp.plot, fn) diff --git a/PlotlyJS/src/kaleido.jl b/PlotlyJS/src/kaleido.jl new file mode 100644 index 0000000..a57cf8e --- /dev/null +++ b/PlotlyJS/src/kaleido.jl @@ -0,0 +1,250 @@ +using Kaleido_jll + +mutable struct Pipes + stdin::Base.PipeEndpoint + stdout::Base.PipeEndpoint + stderr::Base.PipeEndpoint + proc::Base.Process + Pipes() = new() +end + +const P = Pipes() + +const ALL_FORMATS = ["png", "jpeg", "webp", "svg", "pdf", "eps", "json"] +const TEXT_FORMATS = ["svg", "json", "eps"] + +function _restart_kaleido_process() + if isdefined(P, :proc) && process_running(P.proc) + kill(P.proc) + end + _start_kaleido_process() +end + + +function _start_kaleido_process() + global P + try + @info "Try starting kaleido process" + @info "0 ..." + BIN = let + art = Kaleido_jll.artifact_dir + cmd = if Sys.islinux() || Sys.isapple() + joinpath(art, "kaleido") + else + # Windows + joinpath(art, "kaleido.cmd") + end + no_sandbox = "--no-sandbox" + Sys.isapple() ? `$(cmd) plotly --disable-gpu --single-process` : `$(cmd) plotly --disable-gpu $(no_sandbox)` + end + @info "BIN = $(BIN)" + @info "1 ..." + kstdin = Base.PipeEndpoint() + kstdout = Base.PipeEndpoint() + kstderr = Base.PipeEndpoint() + @info "2 ..." + #kproc = run(pipeline(BIN; stdin=kstdin, stdout=kstdout, stderr=kstderr), wait=false) + kproc = run(BIN, kstdin, kstdout, kstderr, wait=false) + @info "3 ..." + @info "kproc = $(kproc)" + process_running(kproc) || error("There was a problem startink up kaleido.") + @info "kproc = $(kproc)" + @info "4 ..." + @info "kstdout = $(kstdout)" + @info "kstderr = $(kstderr)" + @info "kstdin = $(kstdin)" + #close(kstdout.in) + #close(kstderr.in) + #close(kstdin.out) + @info "kstdout = $(kstdout)" + @info "kstderr = $(kstderr)" + @info "kstdin = $(kstdin)" + @info "5 ..." + #Base.start_reading(kstderr.out) + @info "6 ..." + P.stdin = kstdin + P.stdout = kstdout + P.stderr = kstderr + P.proc = kproc + @info "P.stdout = $(P.stdout)" + @info "P.stderr = $(P.stderr)" + @info "P.stdin = $(P.stdin)" + @info "P.proc = $(P.proc)" + + # read startup message and check for errors + @info "7 ..." + @info "P.stdout = $(P.stdout)" + @info "kproc = $(kproc)" + res = readline(P.stdout) + #res = readuntil(kproc, "\n", keep=true) + @info "res = $(res)" + if length(res) == 0 + error("Could not start Kaleido process") + end + + @info "8 ..." + js = JSON.parse(res) + if get(js, "code", 0) != 0 + error("Could not start Kaleido process") + end + catch e + @warn "Kaleido is not available on this system. Julia will be unable to save images of any plots." + @warn "$e" + end + nothing +end + +savefig(p::SyncPlot; kwargs...) = savefig(p.plot; kwargs...) + +function savefig( + p::Plot; + width::Union{Nothing,Int}=nothing, + height::Union{Nothing,Int}=nothing, + scale::Union{Nothing,Real}=nothing, + format::String="png" + )::Vector{UInt8} + if !(format in ALL_FORMATS) + error("Unknown format $format. Expected one of $ALL_FORMATS") + end + + # construct payload + _get(x, def) = x === nothing ? def : x + payload = Dict( + :width => _get(width, 700), + :height => _get(height, 500), + :scale => _get(scale, 1), + :format => format, + :data => p + ) + + _ensure_kaleido_running() + + # convert payload to vector of bytes + bytes = transcode(UInt8, JSON.json(payload)) + write(P.stdin, bytes) + write(P.stdin, transcode(UInt8, "\n")) + flush(P.stdin) + + # read stdout and parse to json + res = readline(P.stdout) + js = JSON.parse(res) + + # check error code + code = get(js, "code", 0) + if code != 0 + msg = get(js, "message", nothing) + error("Transform failed with error code $code: $msg") + end + + # get raw image + img = String(js["result"]) + + # base64 decode if needed, otherwise transcode to vector of byte + if format in TEXT_FORMATS + return transcode(UInt8, img) + else + return base64decode(img) + end +end + + +@inline _get_Plot(p::Plot) = p +@inline _get_Plot(p::SyncPlot) = p.plot + +""" + savefig( + io::IO, + p::Plot; + width::Union{Nothing,Int}=nothing, + height::Union{Nothing,Int}=nothing, + scale::Union{Nothing,Real}=nothing, + format::String="png" + ) + +Save a plot `p` to the io stream `io`. They keyword argument `format` +determines the type of data written to the figure and must be one of +$(join(ALL_FORMATS, ", ")), or html. `scale` sets the +image scale. `width` and `height` set the dimensions, in pixels. Defaults +are taken from `p.layout`, or supplied by plotly +""" +function savefig(io::IO, + p::Union{SyncPlot,Plot}; + width::Union{Nothing,Int}=nothing, + height::Union{Nothing,Int}=nothing, + scale::Union{Nothing,Real}=nothing, + format::String="png") + if format == "html" + return show(io, MIME("text/html"), _get_Plot(p), include_mathjax="cdn", include_plotlyjs="cdn", full_html=true) + end + + bytes = savefig(p, width=width, height=height, scale=scale, format=format) + write(io, bytes) +end + + +""" + savefig( + p::Plot, fn::AbstractString; + format::Union{Nothing,String}=nothing, + width::Union{Nothing,Int}=nothing, + height::Union{Nothing,Int}=nothing, + scale::Union{Nothing,Real}=nothing, + ) + +Save a plot `p` to a file named `fn`. If `format` is given and is one of +$(join(ALL_FORMATS, ", ")), or html; it will be the format of the file. By +default the format is guessed from the extension of `fn`. `scale` sets the +image scale. `width` and `height` set the dimensions, in pixels. Defaults +are taken from `p.layout`, or supplied by plotly +""" +function savefig( + p::Union{SyncPlot,Plot}, fn::AbstractString; + format::Union{Nothing,String}=nothing, + width::Union{Nothing,Int}=nothing, + height::Union{Nothing,Int}=nothing, + scale::Union{Nothing,Real}=nothing, + ) + ext = split(fn, ".")[end] + if format === nothing + format = String(ext) + end + + open(fn, "w") do f + savefig(f, p; format=format, scale=scale, width=width, height=height) + end + return fn +end + +_kaleido_running() = isdefined(P, :stdin) && isopen(P.stdin) && process_running(P.proc) +_ensure_kaleido_running() = !_kaleido_running() && _restart_kaleido_process() + +const _KALEIDO_MIMES = Dict( + "application/pdf" => "pdf", + "image/png" => "png", + "image/svg+xml" => "svg", + "image/eps" => "eps", + "image/jpeg" => "jpeg", + "image/jpeg" => "jpeg", + "application/json" => "json", + "application/json; charset=UTF-8" => "json", +) + +for (mime, fmt) in _KALEIDO_MIMES + @eval function Base.show( + io::IO, ::MIME{Symbol($mime)}, plt::Plot, + width::Union{Nothing,Int}=nothing, + height::Union{Nothing,Int}=nothing, + scale::Union{Nothing,Real}=nothing, + ) + savefig(io, plt, format=$fmt) + end + + @eval function Base.show( + io::IO, ::MIME{Symbol($mime)}, plt::SyncPlot, + width::Union{Nothing,Int}=nothing, + height::Union{Nothing,Int}=nothing, + scale::Union{Nothing,Real}=nothing, + ) + savefig(io, plt.plot, format=$fmt) + end +end diff --git a/PlotlyJS/src/util.jl b/PlotlyJS/src/util.jl new file mode 100644 index 0000000..d17a528 --- /dev/null +++ b/PlotlyJS/src/util.jl @@ -0,0 +1,31 @@ +PlotlyBase.trace_map(p::SyncPlot, axis) = trace_map(p.plot, axis) +JSON.lower(sp::SyncPlot) = sp.plot + +PlotlyBase._is3d(p::SyncPlot) = _is3d(p.plot) + +# subplot methods on syncplot +Base.hcat(sps::SyncPlot...) = SyncPlot(hcat(Plot[sp.plot for sp in sps]...)) +Base.vcat(sps::SyncPlot...) = SyncPlot(vcat(Plot[sp.plot for sp in sps]...)) +Base.hvcat(rows::Tuple{Vararg{Int}}, sps::SyncPlot...) = + SyncPlot(hvcat(rows, Plot[sp.plot for sp in sps]...)) + +function PlotlyBase.add_recession_bands!(p::SyncPlot; kwargs...) + new_shapes = add_recession_bands!(p.plot; kwargs...) + relayout!(p, shapes=new_shapes) + new_shapes +end + +function mgrid(arrays...) + lengths = collect(length.(arrays)) + uno = ones(Int, length(arrays)) + out = [] + for i in 1:length(arrays) + repeats = copy(lengths) + repeats[i] = 1 + + shape = copy(uno) + shape[i] = lengths[i] + push!(out, reshape(arrays[i], shape...) .* ones(repeats...)) + end + out +end diff --git a/PlotlyJS/test/blink.jl b/PlotlyJS/test/blink.jl new file mode 100644 index 0000000..c37929d --- /dev/null +++ b/PlotlyJS/test/blink.jl @@ -0,0 +1,125 @@ +using Blink, WebIO + +t() = scatter(y=rand(10)) +p = plot([t(), t(), t(), t()]) +w = Blink.Window() +body!(w, p.scope) +sleep(3.0) # make sure we give time for svg to render + +# hook up testing observables +on(p.scope["__gd_contents"]) do x end + +function update_data!() + p.scope["__get_gd_contents"][] = "data" + sleep(1) +end + +function update_layout!() + p.scope["__get_gd_contents"][] = "layout" + sleep(1) +end + +@testset "api methods" begin + + @testset "to_image" begin + @test to_image(p)[1:21] == "data:image/png;base64" + @test to_image(p, format="svg")[1:18] == "data:image/svg+xml" + @test to_image(p, format="jpeg")[1:22] =="data:image/jpeg;base64" + @test to_image(p, format="webp")[1:22] =="data:image/webp;base64" + @test_throws ErrorException to_image(p, format="pdf") + @test to_image(p, imageDataOnly=true, format="svg")[1:4] == "