Compare commits

...

43 Commits

Author SHA1 Message Date
mantaohuang
ea8b71898b fix stuff 2022-03-26 18:55:18 -04:00
mantaohuang
4bdee5f6af testing out 2022-03-26 18:37:03 -04:00
mantaohuang
bbbd899c19 testing out 2022-03-26 18:33:43 -04:00
mantaohuang
abcb73b70f Use raw expressions for xlabel, ylabels etc 2022-03-26 18:27:20 -04:00
Giorgio Calderone
9001d5f385 Minor changes in preparation of v1.4.1 2022-01-04 12:06:01 +01:00
Giorgio Calderone
919068e797 Merge branch 'master' of https://github.com/gcalderone/Gnuplot.jl 2022-01-03 13:34:33 +01:00
gcalderone
23c3d663e8
Merge pull request #51 from wentasah/stdout-via-pipe
Don't run gnuplot process connected to stdout
2022-01-03 13:34:25 +01:00
Giorgio Calderone
3f40e38d72 Merge branch 'master' of https://github.com/gcalderone/Gnuplot.jl 2022-01-03 12:41:12 +01:00
gcalderone
443ef0edf7
Merge pull request #49 from wentasah/hist-bounds
Fix BoundsErrors in hist()
2022-01-03 12:40:40 +01:00
gcalderone
ab927d0622
Merge pull request #52 from wentasah/escape-output
Allow using single quotes in output file names
2022-01-03 10:45:19 +01:00
Giorgio Calderone
622597c589 Merge branch 'master' of https://github.com/gcalderone/Gnuplot.jl 2022-01-03 10:39:40 +01:00
Michal Sojka
ce00617796 Allow using single quotes in output file names
Gnuplot single-quoted strings have to escape single-quote characters
by doubling them.
2021-12-13 18:58:24 +01:00
Giorgio Calderone
e70c30dd13 Handle the case where an implicit recipe returns a Vector{PlotElement} 2021-12-05 15:59:48 +01:00
Michal Sojka
799154f53c Add doctest of dumb terminal
This serves two purposes:

1. It demonstrates the functionality of the dumb terminal.
2. It checks that the previous commit works.
2021-12-05 11:53:30 +01:00
Michal Sojka
d02c211e99 Don't run gnuplot process connected to stdout
This change fixes incompatibility of Gnuplot.jl with Documenter.jl
versions 0.27.0 and above. Without this change, Gnuplot.jl has at
least these problems:

1. When building Gnuplot.jl documentation, the process blocks and
   never finishes.

2. When using Gnuplot.jl in docstrings in other code, running
   `doctest` blocks and never finishes.

The reason is that Documenter uses a new version of IOCapture.jl,
which contains this commit:
6cb4cdff34.

Documenter evaluates code snippets from the documentation with
`stdout` redirected to a pipe to show the command's output. The
mentioned commit changes the behavior so that now capturing waits
until the pipe is closed. The problem with Gnuplot.jl is that when the
gnuplot process is started as a part of the execution of documentation
code snippet, its `stdout` is bound to Documenter's pipe. The pipe is
not closed until the gnuplot process exits, which does not happen
unless the code snippet calls `Gnuplot.quit` explicitly. Therefore
Documenter blocks indefinitely.

This can be demonstrated by storing the following code in `test.jl`

    module GnuplotDocTest
    """
    ```jldoctest; setup = :(using Gnuplot)
    julia> @gp rand(100)

    ```
    """
    test() = nothing
    end

    using Documenter
    doctest(pwd(), [GnuplotDocTest])

and running `julia test.jl`.

To fix this problem, we run the gnuplot process with stdout redirected
to a pipe and create an asynchronous task, which reads the gnuplot's
stdout and writes it to Julia's current stdout.

Correctness of this approach can be verified by running:

    using Gnuplot
    Gnuplot.options.term = "dumb"
    @gp "plot sin(x)"

Dumb terminal prints to stdout and the above command shows the graph
on Julia's stdout too. In the next commit, we add the above code as a
doctest.
2021-12-05 11:51:29 +01:00
Michal Sojka
67c8781f2b Fix another hist BoundsError
This fixes the error with `hist([1,1,1], bs=1)`:

    ERROR: BoundsError: attempt to access 0-element Vector{Int64} at index [0]
    Stacktrace:
     [1] getindex
       @ ./array.jl:801 [inlined]
     [2] hist(v::Vector{Int64}; range::Vector{Float64}, bs::Int64, nbins::Int64, pad::Bool)
       @ Gnuplot ~/.julia/dev/Gnuplot/src/Gnuplot.jl:1864
     [3] top-level scope
       @ REPL[50]:1
2021-09-06 16:53:40 +02:00
Michal Sojka
db8dcfc433 Fix bounds error in hist recipe
When running hist([1,2,3], bs=2), the following error is produced:

ERROR: BoundsError: attempt to access 1-element Vector{Float64} at index [2]
Stacktrace:
 [1] getindex
   @ ./array.jl:801 [inlined]
 [2] hist(v::Vector{Int64}; range::Vector{Float64}, bs::Int64, nbins::Int64, pad::Bool)
   @ Gnuplot ~/.julia/dev/Gnuplot/src/Gnuplot.jl:1873
 [3] top-level scope
   @ REPL[25]:1
2021-09-06 16:53:40 +02:00
gcalderone
04484adc22
Merge pull request #44 from wentasah/requires-jl
docs: Suggest using Requires.jl for automatic settings of package options
2021-05-25 16:04:11 +02:00
Michal Sojka
658e5f422c docs: Suggest using Requires.jl for automatic settings of package options
Using the @gnuplotrc macro for collecting user's preferred setup works
well, but it is a bit annoying when Julia needs to be restarted
often (e.g. due to crashes). Using Requires.jl allows the user to
forget about calling @gnuplotrc; the initialization happens
automatically, whenever the Gnuplot package is loaded.
2021-05-25 15:01:45 +02:00
Giorgio Calderone
9327492aa1 Updated 2021-05-06 00:14:01 +02:00
Giorgio Calderone
0567acc60e Bump version to 1.4.0 (to meet automerge guidelines) 2021-05-05 23:48:11 +02:00
Giorgio Calderone
74e195f290 Updated 2021-05-05 12:19:04 +02:00
Giorgio Calderone
875773fd3d Docs updated 2021-05-05 12:03:13 +02:00
Giorgio Calderone
53159f89e1 Bugfix; Allow missing as input to hist(); Updated version() 2021-05-05 11:59:15 +02:00
Giorgio Calderone
54db30cc32 Bump version 2021-05-05 00:58:14 +02:00
Giorgio Calderone
364e5281bd Merge branch 'master' of https://github.com/gcalderone/Gnuplot.jl 2021-05-05 00:53:09 +02:00
Giorgio Calderone
e8a6b21df6 Updated dependencies; Accept missing values on input arrays (if eltype <: AbstractFloat) 2021-05-05 00:52:56 +02:00
gcalderone
6c6b889df6
Merge pull request #43 from wentasah/vscode
VS Code support
2021-04-08 17:40:36 +02:00
Giorgio Calderone
5c46e35fea Updated DataStructures dependency 2021-04-01 14:04:40 +02:00
Michal Sojka
34af493921 Make the figures in VS Code bigger
Without this change, the figures in VS Code are too small.
2021-03-30 20:11:05 +02:00
Michal Sojka
f2ef5373b0 Show plots in internal VS Code plot pane
With this change, when Gnuplot.jl is used within VSCode, the plot
shows in VSCode plot pane instead of in a separate Gnuplot window.

Note that when compared to IJulia and Juno, we do not test for active
VS Code connection. I don't think it is necessary, but if it turns out
to be needed later, it can be done with

    isopen(VSCodeServer.conn_endpoint[])
2021-03-30 19:43:27 +02:00
Giorgio Calderone
bc74aa0db4 Accept AbstractArrays which can be converted to actual arrays 2021-01-02 00:15:39 +01:00
Giorgio Calderone
b7a15290d3 Bugfix 2020-10-06 10:21:46 +02:00
Giorgio Calderone
f62b569560 Fix #28 and similar issues 2020-10-05 01:14:18 +02:00
gcalderone
584144e2ec
Merge pull request #30 from PallHaraldsson/patch-1
Juno and Jypyther in docs
2020-10-05 00:00:36 +02:00
gcalderone
03953c0ad6
Merge pull request #35 from jarvist/master
Add check for Pluto.jl interactive notebook.
2020-10-04 23:55:14 +02:00
Jarvist Moore Frost
084dd63059 Add check for Pluto.jl interactive notebook. 2020-09-21 21:02:08 +01:00
Páll Haraldsson
50141d1b0e
Juno and Jypyther in docs
[ci skip]
2020-07-13 11:38:23 +00:00
Giorgio Calderone
83c59ae682 Set utf8 encoding on gnuplot start 2020-05-05 11:44:08 +02:00
gcalderone
1877deef7f
Merge pull request #26 from lyon-fnal/master
Fix the string indexing error and problems with multiplot on JupyterLab
2020-05-05 00:59:08 +02:00
Adam Lyon
67a5583c29 Fixes #25 2020-05-04 15:59:21 -05:00
Adam Lyon
69644f99ba Fix #24 2020-05-04 15:58:59 -05:00
Giorgio Calderone
2713f8517e Updated 2020-04-29 12:24:46 +02:00
14 changed files with 266 additions and 108 deletions

View File

@ -6,15 +6,15 @@ os:
# - osx
julia:
- 1.2
- nightly
- 1.5
# - nightly
notifications:
email: false
matrix:
allow_failures:
- julia: nightly
#matrix:
# allow_failures:
# - julia: nightly
addons:
apt:

View File

@ -1,6 +1,38 @@
# Version 1.3.0 (released on: Apr. 28, 2020)
# Version 1.4.1 (released on: )
- New features:
* Implicit recipes can now returns a `Vector{PlotElement}`;
* Allow using single quotes in output file names (#52);
* New function: `palette_levels()` can be used to modify palette levels before passing them to gnuplot;
- Bugfix:
* Fixed `BoundsErrors` in `hist()` (#49);
* Fixed problem when generating documentation (#51);
# Version 1.4.0 (released on: May 5, 2021)
- New features:
* Missing values are accepted if the input arrays have `eltype <:
AbstractFloat`;
* Missing values are also accepted in calls to `hist`;
* VSCode and Pluto sessions are now properly handled (#35 and #43);
- Bugfix:
* Multiplot were not displayed in Jupyter (#25);
* `gpvars()` fails if gnuplot character encoding is utf8
(#24);
# Version 1.3.0 (released on: Apr. 29, 2020)
- New features:
* The new `dgrid3d()` allows to interpolate scattered 2D data on a
2D regular grid;
* The `Options` structure features a new `mime` field containing a
dictionary to map a MIME type to gnuplot terminals;

View File

@ -1,6 +1,6 @@
name = "Gnuplot"
uuid = "dc211083-a33a-5b79-959f-2ff34033469d"
version = "1.3.0"
version = "1.4.1"
[deps]
ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
@ -14,11 +14,11 @@ StructC14N = "d2514e9c-36c4-5b8e-97e2-51e7675c221c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
[compat]
ColorSchemes = "^3.5"
ColorTypes = "^0.10"
ColorSchemes = "^3.12"
ColorTypes = "^0.11"
Colors = "^0.12"
DataStructures = "^0.17"
DataStructures = "^0.18"
ReplMaker = "^0.2"
StatsBase = "^0.33"
StructC14N = "^0.3"
julia = "^1.2"
julia = "^1.6"

View File

@ -3,10 +3,10 @@
[![Build Status](https://travis-ci.org/gcalderone/Gnuplot.jl.svg?branch=master)](https://travis-ci.org/gcalderone/Gnuplot.jl)
[![License](http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](LICENSE.md)
[![DocumentationStatus](https://img.shields.io/badge/docs-stable-blue.svg?style=flat)](https://gcalderone.github.io/Gnuplot.jl/v1.3.0/)
[![DocumentationStatus](https://img.shields.io/badge/docs-stable-blue.svg?style=flat)](https://gcalderone.github.io/Gnuplot.jl/v1.4.0/index.html)
**Gnuplot.jl** is a simple package able to send both data and commands from Julia to an underlying [gnuplot](http://gnuplot.sourceforge.net/) process. Its main purpose it to provide a fast and powerful data visualization framework, using an extremely concise Julia syntax.
**Gnuplot.jl** is a simple package able to send both data and commands from Julia to an underlying [gnuplot](http://gnuplot.sourceforge.net/) process. Its main purpose it to provide a fast and powerful data visualization framework, using an extremely concise Julia syntax. It also has automatic display of plots in Jupyter, Juno and VS Code.
## Installation
@ -21,9 +21,9 @@ You may check the installed **Gnuplot.jl** version with:
```julia
]st Gnuplot
```
If the displayed version is not v1.3.0 you are probably having a dependency conflict. In this case try forcing installation of the latest version with:
If the displayed version is not v1.4.0 you are probably having a dependency conflict. In this case try forcing installation of the latest version with:
```julia
]add Gnuplot@1.3.0
]add Gnuplot@1.4.0
```
and check which package is causing the conflict.
@ -37,7 +37,7 @@ test_terminal()
## Quick start
The following examples are supposed to be self-explaining. See [documentation](https://gcalderone.github.io/Gnuplot.jl/v1.3.0/) for further informations.
The following examples are supposed to be self-explaining. See [documentation](https://gcalderone.github.io/Gnuplot.jl/v1.4.0/) for further informations.
### A simple parabola
```julia

View File

@ -21,6 +21,7 @@ gpvars
hist
linetypes
palette
palette_levels
palette_names
recipe
save

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -210,6 +210,16 @@ saveas("basic008a") # hide
```
![](assets/basic008a.png)
The palette levels may be easily stretched by using the [`palette_levels()`](@ref) and modifying the numeric levels, e.g.:
```@example abc
x = 0:0.1:10pi
v, l, n = palette_levels(:viridis)
@gsp palette(v.^0.25, l, n) cbr=[-1,1].*30 :-
@gsp :- x x.*sin.(x) x.*cos.(x) x./20 "w p pt 7 ps var lc pal"
saveas("basic008b") # hide
```
![](assets/basic008b.png)
The list of all available palette can be retrieved with [`palette_names()`](@ref):
```@repl abc
palette_names()

View File

@ -19,11 +19,11 @@ Check **Gnuplot.jl** version with:
```julia-repl
julia> ]st Gnuplot
Status `~/.julia/environments/v1.4/Project.toml`
[dc211083] Gnuplot v1.3.0
[dc211083] Gnuplot v1.4.1
```
If the displayed version is not `v1.3.0` you are probably having a dependency conflict. In this case try forcing installation of the latest version with:
If the displayed version is not `v1.4.1` you are probably having a dependency conflict. In this case try forcing installation of the latest version with:
```julia-repl
julia> ]add Gnuplot@1.3.0
julia> ]add Gnuplot@1.4.1
```
and check which package is causing the conflict.

View File

@ -70,12 +70,11 @@ Each line reports the package name (`GNUPLOT`), the session name (`default`), th
## Package initialization
If you use **Gnuplot.jl** frequently you may find convenient to collect all the package settings ([Options](@ref)) in a single place, to quickly recall them in a Julia session. A possibility is to put the following code in the `~/.julia/config/startup.jl` initialization file (further info [here](https://docs.julialang.org/en/v1/stdlib/REPL/)):
If you use **Gnuplot.jl** frequently you may find convenient to automatically apply the package settings ([Options](@ref)) whenever the package is loaded. A possibility is to use [Requires.jl](https://github.com/JuliaPackaging/Requires.jl) and put the following code in the `~/.julia/config/startup.jl` initialization file (further info [here](https://docs.julialang.org/en/v1/stdlib/REPL/)):
```julia
macro gnuplotrc()
return :(
using Gnuplot;
using Requires
@require Gnuplot="dc211083-a33a-5b79-959f-2ff34033469d" begin
@info "Custom Gnuplot initialization"
# Uncomment the following if you don't have the gnuplot
# executable installed on your platform:
#Gnuplot.options.dry = true;
@ -103,17 +102,13 @@ macro gnuplotrc()
# Set the default linetypes
empty!(Gnuplot.options.init);
push!(Gnuplot.options.init, linetypes(:Set1_5, lw=1.5, ps=1.5));
push!(Gnuplot.options.init, Gnuplot.linetypes(:Set1_5, lw=1.5, ps=1.5));
# Initialize the gnuplot REPL using the provided `start_key`.
if Gnuplot.options.gpviewer;
Gnuplot.repl_init(start_key='>');
end;
)
end
```
At the Julia prompt you may load the package and the associated settings by typing:
```julia
julia> @gnuplotrc
```
and you're ready to go.
The above code will be automatically when you first load the package with `using Gnuplot`.

View File

@ -125,7 +125,7 @@ end
with only one mandatory argument. In order to exploit the optional keyword we can explicitly invoke the recipe as follows:
```@example abc
img = testimage("walkbridge");
@gp palette(:gray) recipe(img, "flipy rot=15deg")
@gp palette(:gray1) recipe(img, "flipy rot=15deg")
saveas("recipes007c") # hide
```
![](assets/recipes007c.png)

View File

@ -1,6 +1,6 @@
# Style Guide
The **Gnuplot.jl** loose syntax allows to create a plot using very different approaches. While this was one of the initial purposes for the package, it may lead to decreased code readability if not used judiciously.
The **Gnuplot.jl** loose syntax allows to create a plot using very different approaches. While this was one of the initial purposes for the package, it may lead to a reduced code readability if not used judiciously.
Here I will summarize a few, non-mandatory, guidelines which allows to maintain a neat syntax and a high readability:

View File

@ -4,11 +4,7 @@ Gnuplot provides dozens of terminals to display plots or export them into files
To use a specific terminal for interactive use you may either set it as initialization command for all new session with (see [Options](@ref)):
```julia
Gnuplot.options.term = "wxt")
```
or directly send the command to a specific session (see [Direct command execution](@ref))
```julia
gpexec("set term wxt")
Gnuplot.options.term = "wxt"
```
See official [gnuplot documentation](http://gnuplot.sourceforge.net/documentation.html) for further info on terminals and their options.
@ -16,13 +12,13 @@ See official [gnuplot documentation](http://gnuplot.sourceforge.net/documentatio
## Interactive terminals (`wxt` and `qt`)
The multiplatform `wxt` and `qt` terminals are among the most widely used ones for their nicely looking outputs on display and for their interactive capabilities.
You may set them as terminal with:
You may use such terminals with:
```
"set term wxt size 800,600"
Gnuplot.options.term = "wxt size 800,600"
```
or
```
"set term qt size 800,600"
Gnuplot.options.term = "qt size 800,600"
```
(the `size 800,600` is optional and can be omitted).
@ -30,9 +26,35 @@ Press the `h` key on the window to display an help message with all available ke
## Plot in a terminal application (`dumb`, `sixel` and `sixelgd`)
Gnuplot supports plotting in a terminal application, with no need for X11 or other GUI support, via the `dumb`, `sixel` and `sixelgd` terminals. These are extremely useful when you run Julia on a remote shell through `ssh`, with no X11 forwarding.
Gnuplot supports plotting in a terminal application, with no need for X11 or other GUI support, via the `dumb`, `sixel` and `sixelgd` terminals. These are extremely useful when you run Julia on a remote shell through `ssh`, with no X11 forwarding. The `dumb` terminal uses ASCII characters to draw a plot, while `sixel` and `sixelgd` actually use bitmaps (but require Sixel support to be enabled in the terminal, e.g. `xterm -ti vt340`).
The `dumb` terminal uses ASCII characters to draw a plot, while `sixel` and `sixelgd` actually use bitmaps (but require Sixel support to be enabled in the terminal, e.g. `xterm -ti vt340`). A sixel plot on `xterm` looks as follows:
Dumb terminal can be used as follows:
```jldoctest; setup = :(using Gnuplot)
julia> origterm = Gnuplot.options.term;
julia> Gnuplot.options.term = "dumb size 60,15";
julia> @gp "plot sin(x)"
1 +-------------------------------------------------+
0.8 |-+ *+ * + ** ** + * * +-|
0.6 |-+ * ** * * sin(x) *******-|
0.4 |*+ * * * * * *+-|
0.2 |*+ * * * * * *-|
0 |*+ * * * * * *-|
| * * * * * * *|
-0.2 |-* * * * * * +*|
-0.4 |-+* * * * * * +*|
-0.6 |-+* * * * ** * +-|
-0.8 |-+ * * + ** ** + * * +-|
-1 +-------------------------------------------------+
-10 -5 0 5 10
julia> Gnuplot.options.term = origterm;
```
A sixel plot on `xterm` looks as follows:
![](assets/sixelgd.png)
The above terminals are available if gnuplot has been compiled with the `--with-bitmap-terminals` option enabled and Libgd (only for `sixelgd`).
@ -58,7 +80,7 @@ Gnuplot is also able to export vector (i.e. non-raster) plots through the `svg`
The `cairolatex` terminal allows to produce high quality plots by splitting the output into a PDF file (containing a rasterized image of a plot) and a `.tex` file (containing all the text as ``\LaTeX`` code). The following example shows how to write plot tics and an equation in ``\LaTeX``:
```julia
x = LinRange(-2pi, 2pi, 1000)
@gp t="Polynomial approximation of sin(x)" "set style fill transparent solid 0.6 noborder"
@gp tit="Polynomial approximation of sin(x)" "set style fill transparent solid 0.6 noborder"
@gp :- raw"""set xtics ('$-\pi$' -pi, '$-\pi/2$' -pi/2, 0, '$\pi/2$' pi/2, '$\pi$' pi)"""
@gp :- xr=3.8.*[-1, 1] yr=[-1.5,1.5] key="box opaque left horiz" linetypes(:Blues_3) "set grid front"
latex = raw"""\begin{minipage}[c]{\textwidth}\begin{equation*}""" *

View File

@ -7,7 +7,7 @@ import Base.reset
import Base.write
import Base.show
export session_names, dataset_names, palette_names, linetypes, palette,
export session_names, dataset_names, palette_names, linetypes, palette_levels, palette,
terminal, terminals, test_terminal,
stats, @gp, @gsp, save, gpexec,
boxxy, contourlines, dgrid3d, hist, recipe, gpvars, gpmargins, gpranges
@ -236,12 +236,18 @@ const sessions = OrderedDict{Symbol, Session}()
const options = Options()
function __init__()
# Check whether we are running in a IJulia or Juno session.
# Check whether we are running in an IJulia, Juno, VSCode or Pluto session.
# (copied from Gaston.jl).
options.gpviewer = !(
((isdefined(Main, :IJulia) && Main.IJulia.inited) ||
(isdefined(Main, :Juno) && Main.Juno.isactive()))
(isdefined(Main, :Juno) && Main.Juno.isactive()) ||
(isdefined(Main, :VSCodeServer)) ||
(isdefined(Main, :PlutoRunner)) )
)
if isdefined(Main, :VSCodeServer)
# VS Code shows "dynamic" plots with fixed and small size :-(
options.mime[MIME"image/svg+xml"] = replace(options.mime[MIME"image/svg+xml"], "dynamic" => "")
end
end
@ -277,11 +283,11 @@ function parseKeywords(; kwargs...)
ismissing(kw.zrange ) || (push!(out, replace("set zrange [" * join(kw.zrange , ":") * "]", "NaN"=>"*")))
ismissing(kw.cbrange) || (push!(out, replace("set cbrange [" * join(kw.cbrange, ":") * "]", "NaN"=>"*")))
ismissing(kw.key ) || (push!(out, "set key " * kw.key * ""))
ismissing(kw.title ) || (push!(out, "set title \"" * kw.title * "\""))
ismissing(kw.xlabel ) || (push!(out, "set xlabel \"" * kw.xlabel * "\""))
ismissing(kw.ylabel ) || (push!(out, "set ylabel \"" * kw.ylabel * "\""))
ismissing(kw.zlabel ) || (push!(out, "set zlabel \"" * kw.zlabel * "\""))
ismissing(kw.cblabel) || (push!(out, "set cblabel \"" * kw.cblabel * "\""))
ismissing(kw.title ) || (push!(out, "set title '" * kw.title * "'"))
ismissing(kw.xlabel ) || (push!(out, "set xlabel '" * kw.xlabel * "'"))
ismissing(kw.ylabel ) || (push!(out, "set ylabel '" * kw.ylabel * "'"))
ismissing(kw.zlabel ) || (push!(out, "set zlabel '" * kw.zlabel * "'"))
ismissing(kw.cblabel) || (push!(out, "set cblabel '" * kw.cblabel * "'"))
ismissing(kw.xlog ) || (push!(out, (kw.xlog ? "" : "un") * "set logscale x"))
ismissing(kw.ylog ) || (push!(out, (kw.ylog ? "" : "un") * "set logscale y"))
ismissing(kw.zlog ) || (push!(out, (kw.zlog ? "" : "un") * "set logscale z"))
@ -298,7 +304,6 @@ function parseKeywords(; kwargs...)
ismissing(kw.rmargin) || push!(out, (kw.rmargin == "" ? "unset rmargin" : "set rmargin at screen $(kw.rmargin)"))
ismissing(kw.bmargin) || push!(out, (kw.bmargin == "" ? "unset bmargin" : "set bmargin at screen $(kw.bmargin)"))
ismissing(kw.tmargin) || push!(out, (kw.tmargin == "" ? "unset tmargin" : "set tmargin at screen $(kw.tmargin)"))
return join(out, ";\n")
end
@ -514,7 +519,6 @@ function readTask(gp::GPSession)
delete!(sessions, gp.sid)
end
function GPSession(sid::Symbol)
session = DrySession(sid)
if !options.dry
@ -529,13 +533,16 @@ function GPSession(sid::Symbol)
end
pin = Base.Pipe()
pout = Base.Pipe()
perr = Base.Pipe()
proc = run(pipeline(`$(options.cmd)`, stdin=pin, stdout=stdout, stderr=perr), wait=false)
proc = run(pipeline(`$(options.cmd)`, stdin=pin, stdout=pout, stderr=perr), wait=false)
chan = Channel{String}(32)
# Close unused sides of the pipes
Base.close(pout.in)
Base.close(perr.in)
Base.close(pin.out)
Base.start_reading(pout.out)
Base.start_reading(perr.out)
out = GPSession(getfield.(Ref(session), fieldnames(DrySession))...,
@ -544,11 +551,19 @@ function GPSession(sid::Symbol)
# Start reading tasks
@async readTask(out)
@async while !eof(pout) # see PR #51
write(stdout, readavailable(pout))
end
# Read gnuplot default terminal
if options.term == ""
options.term = terminal()
end
# The stderr of the gnuplot process goes to Julia which can parse
# UTF8 characters (regardless of the terminal).
gpexec("set encoding utf8")
return out
end
@ -698,7 +713,7 @@ end
function DatasetBin(cols::Vararg{AbstractVector, N}) where N
source = "binary record=$(length(cols[1])) format='"
types = Vector{DataType}()
(length(cols) == 1) && (source *= "%int")
#(length(cols) == 1) && (source *= "%int")
for i in 1:length(cols)
@assert length(cols[1]) == length(cols[i])
if isa(cols[i][1], Int32); push!(types, Int32); source *= "%int"
@ -715,7 +730,7 @@ function DatasetBin(cols::Vararg{AbstractVector, N}) where N
(path, io) = mktemp()
source = " '$path' $source"
for row in 1:length(cols[1])
(length(cols) == 1) && (write(io, convert(Int32, row)))
#(length(cols) == 1) && (write(io, convert(Int32, row)))
for col in 1:length(cols)
write(io, convert(types[col], cols[col][row]))
end
@ -803,7 +818,7 @@ function useBinaryMethod(args...)
elseif options.preferred_format == :auto
if (length(args) == 1) && isa(args[1], AbstractMatrix)
binary = true
elseif all(ndims.(args) .== 1)
elseif all(ndims.(args) .== 1) && all(Base.:<:.(eltype.(args), Real))
s = sum(length.(args))
if s > 1e4
binary = true
@ -911,9 +926,10 @@ function execall(gp::GPSession; term::AbstractString="", output::AbstractString=
if term != ""
former_term = writeread(gp, "print GPVAL_TERM")[1]
former_opts = writeread(gp, "print GPVAL_TERMOPTIONS")[1]
gpexec(gp, "unset multiplot")
gpexec(gp, "set term $term")
end
(output != "") && gpexec(gp, "set output '$output'")
(output != "") && gpexec(gp, "set output '$(replace(output, "'" => "''"))'")
# printstyled("Plotting with terminal: " * terminal() * "\n", color=:blue, bold=true)
@ -1105,15 +1121,24 @@ function parseArguments(_args...)
end
insert!(args, pos, string(strip(arg[1])) => nothing)
elseif isa(arg, AbstractArray) && # ==> a dataset column
((valtype(arg) <: Real) ||
(valtype(arg) <: AbstractString)) ;
((nonmissingtype(eltype(arg)) <: Real) ||
(nonmissingtype(eltype(arg)) <: AbstractString)) ;
elseif isa(arg, Real) # ==> a dataset column with only one row
args[pos] = [arg]
elseif isa(arg, Dataset) ; # ==> a Dataset object
elseif hasmethod(recipe, tuple(typeof(arg))) # ==> implicit recipe
# @info which(recipe, tuple(typeof(arg))) # debug
deleteat!(args, pos)
insert!(args, pos, recipe(arg))
pe = recipe(arg)
if isa(pe, PlotElement)
insert!(args, pos, pe)
elseif isa(pe, Vector{PlotElement})
for i in 1:length(pe)
insert!(args, pos, pe[i])
end
else
error("Recipe must return a PlotElement or Vector{PlotElement}")
end
continue
elseif isa(arg, Vector{PlotElement}) # ==> explicit recipe (vector)
deleteat!(args, pos)
@ -1128,40 +1153,54 @@ function parseArguments(_args...)
pos += 1
end
# Third pass: convert data into Dataset objetcs
# Third pass: convert data into Dataset objects
pos = 1
accum = Vector{AbstractArray}()
while pos <= length(args)
arg = args[pos]
if isa(arg, AbstractArray) && # ==> beginning of a dataset
((valtype(arg) <: Real) ||
(valtype(arg) <: AbstractString))
taken = false
# Collect all data
accum = Vector{AbstractArray}()
while isa(arg, AbstractArray) &&
((valtype(arg) <: Real) ||
(valtype(arg) <: AbstractString))
if isa(arg, AbstractArray)
if nonmissingtype(eltype(arg)) != eltype(arg)
@assert nonmissingtype(eltype(arg)) <: AbstractFloat "Missing values are supported only on arrays of floats"
arg = replace(arg, missing => NaN)
end
tt = eltype(arg)
# Try to convert into Int, Float64 and String
if (tt <: Integer) && !(tt <: Int)
arg = convert(Array{Int}, arg)
elseif (tt <: AbstractFloat) && !(tt <: Float64)
arg = convert(Array{Float64}, arg)
elseif (tt <: AbstractString) && !(tt <: String)
arg = convert(Array{String}, arg)
end
tt = eltype(arg)
if (tt <: Real) ||
(tt <: AbstractString)
push!(accum, arg)
deleteat!(args, pos)
if pos <= length(args)
arg = args[pos]
else
break
taken = true
end
end
if !taken || (pos > length(args))
if length(accum) > 0
mm = extrema(length.(accum))
if mm[1] == 0
# empty Dataset
if mm[1] == 0 # empty Dataset
@assert mm[1] == mm[2] "At least one input array is empty, while other(s) are not"
d = DatasetEmpty()
else
d = Dataset(accum)
end
insert!(args, pos, d)
empty!(accum)
end
pos += 1
end
end
# Fourth pass: collect PlotElement objects
mid = 0
@ -1321,7 +1360,7 @@ end
Return the **Gnuplot.jl** package version.
"""
version() = v"1.3.0"
version() = v"1.4.1"
# ---------------------------------------------------------------------
"""
@ -1672,6 +1711,34 @@ function linetypes(cmap::ColorScheme; lw=1, ps=1, dashed=false, rev=false)
end
"""
palette_levels(cmap::ColorScheme; rev=false, smooth=false)
palette_levels(s::Symbol; rev=false, smooth=false)
Convert a `ColorScheme` object into a `Tuple{Vector{Float64}, Vector{String}, Int}` containing:
- the numeric levels (between 0 and 1 included) corresponding to colors in the palette;
- the corresponding colors (as hex strings);
- the total number of different colors in the palette.
If the argument is a `Symbol` it is interpreted as the name of one of the predefined schemes in [ColorSchemes](https://juliagraphics.github.io/ColorSchemes.jl/stable/basics/#Pre-defined-schemes-1).
If `rev=true` the palette is reversed. If `smooth=true` the palette is interpolated in 256 levels.
"""
palette_levels(s::Symbol; kwargs...) = palette_levels(colorschemes[s]; kwargs...)
function palette_levels(cmap::ColorScheme; rev=false, smooth=false)
levels = OrderedDict{Float64, String}()
for x in LinRange(0, 1, (smooth ? 256 : length(cmap.colors)))
if rev
color = get(cmap, 1-x)
else
color = get(cmap, x)
end
levels[x] = "#" * Colors.hex(color)
end
return (collect(keys(levels)), collect(values(levels)), length(cmap.colors))
end
"""
palette(cmap::ColorScheme; rev=false, smooth=false)
palette(s::Symbol; rev=false, smooth=false)
@ -1682,19 +1749,13 @@ If the argument is a `Symbol` it is interpreted as the name of one of the predef
If `rev=true` the palette is reversed. If `smooth=true` the palette is interpolated in 256 levels.
"""
function palette(values::Vector{Float64}, levels::Vector{String}, ncolors::Int)
str = string.(values) .* " '" .* levels .* "'"
return "set palette defined (" * join(str, ", ") * ")\nset palette maxcol $(ncolors)\n"
end
palette(s::Symbol; kwargs...) = palette(colorschemes[s]; kwargs...)
function palette(cmap::ColorScheme; rev=false, smooth=false)
levels = Vector{String}()
for x in LinRange(0, 1, (smooth ? 256 : length(cmap.colors)))
if rev
color = get(cmap, 1-x)
else
color = get(cmap, x)
end
push!(levels, "$x '#" * Colors.hex(color) * "'")
end
return "set palette defined (" * join(levels, ", ") * ")\nset palette maxcol $(length(cmap.colors))\n"
end
palette(cmap::ColorScheme; kwargs...) =
palette(palette_levels(cmap; kwargs...)...)
# --------------------------------------------------------------------
@ -1820,16 +1881,20 @@ function hist(v::Vector{T}; range=[NaN,NaN], bs=NaN, nbins=0, pad=true) where T
if sum(hh.weights) < length(i)
j = findall(v[i] .== range[2])
@assert length(j) == (length(i) - sum(hh.weights))
if length(hh.weights) > 0
hh.weights[end] += length(j)
else
push!(hh.weights, length(j))
end
end
else
hh = fit(Histogram, v[i], closed=:left)
end
@assert sum(hh.weights) == length(i)
x = collect(hh.edges[1])
x = (x[1:end-1] .+ x[2:end]) ./ 2
binsize = isfinite(bs) ? bs : x[2] - x[1]
length(x) > 1 && (x = (x[1:end-1] .+ x[2:end]) ./ 2)
h = hh.weights
binsize = x[2] - x[1]
if pad
x = [x[1]-binsize, x..., x[end]+binsize]
h = [0, h..., 0]
@ -1893,6 +1958,35 @@ function hist(v1::Vector{T1}, v2::Vector{T2};
return Histogram2D(x1, x2, hh.weights, binsize1, binsize2)
end
# Allow missing values in input
function hist(v::Vector{Union{Missing,T}}; kw...) where T <: Real
ii = findall(.!ismissing.(v))
@info "Neglecting missing values ($(length(v) - length(ii)))"
hist(convert(Vector{T}, v[ii]); kw...)
end
function hist(v1::Vector{Union{Missing,T1}}, v2::Vector{T2}; kw...) where {T1 <: Real, T2 <: Real}
ii = findall(.!ismissing.(v1) .&
.!ismissing.(v2) )
@info "Neglecting missing values ($(length(v1) - length(ii)))"
hist(convert(Vector{T1}, v1[ii]), convert(Vector{T2}, v2[ii]), kw...)
end
function hist(v1::Vector{T1}, v2::Vector{Union{Missing, T2}}; kw...) where {T1 <: Real, T2 <: Real}
ii = findall(.!ismissing.(v1) .&
.!ismissing.(v2) )
@info "Neglecting missing values ($(length(v1) - length(ii)))"
hist(convert(Vector{T1}, v1[ii]), convert(Vector{T2}, v2[ii]), kw...)
end
function hist(v1::Vector{Union{Missing,T1}}, v2::Vector{Union{Missing,T2}}; kw...) where {T1 <: Real, T2 <: Real}
ii = findall(.!ismissing.(v1) .&
.!ismissing.(v2) )
@info "Neglecting missing values ($(length(v1) - length(ii)))"
hist(convert(Vector{T1}, v1[ii]), convert(Vector{T2}, v2[ii]), kw...)
end
# --------------------------------------------------------------------
"""
@ -2254,7 +2348,7 @@ function gpvars(sid::Symbol)
if length(s) == 2
key = Symbol(s[1])
if s[2][1] == '"'
out[key] = s[2][2:end-1]
out[key] = s[2][2:prevind(s[2], end, 1)]
else
try
out[key] = Meta.parse(s[2])

View File

@ -286,4 +286,8 @@ Gnuplot.quit(:default)
Gnuplot.options.dry = true
@gp hist(randn(1000))
# Various hist() corner cases
@gp hist([1,2,3], bs=2)
@gp hist([1,1,1], bs=1)
Gnuplot.quitall()