Add plots and concat test
This commit is contained in:
parent
a28db7bc32
commit
2be5cd88bc
1
dub.sdl
1
dub.sdl
|
@ -5,6 +5,7 @@ copyright "Copyright © 2019, Les De Ridder"
|
|||
license "NCSA"
|
||||
dependency "emsi_containers" version="~>0.7.0"
|
||||
dependency "collections" version="~>0.1.0"
|
||||
dependency "matplotlib-d" path="matplotlib-d"
|
||||
|
||||
-- :/
|
||||
importPaths "/home/lesderid/repos/d/druntime/src"
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"versions": {
|
||||
"collections": "0.1.0",
|
||||
"emsi_containers": "0.7.0",
|
||||
"mir-algorithm": "3.5.0-alpha09",
|
||||
"mir-core": "0.3.5",
|
||||
"matplotlib-d": {"path":"matplotlib-d"},
|
||||
"stdx-allocator": "2.77.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
.dub
|
||||
docs.json
|
||||
__dummy.html
|
||||
*.o
|
||||
*.obj
|
||||
__test__*__
|
||||
*~
|
||||
views/
|
||||
build/
|
||||
README.html
|
||||
*.png
|
|
@ -0,0 +1,17 @@
|
|||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
language: d
|
||||
|
||||
d:
|
||||
- ldc2
|
||||
- dmd
|
||||
|
||||
before_install:
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install python-tk; fi
|
||||
- sudo pip install matplotlib
|
||||
|
||||
|
||||
script:
|
||||
- dub test --compiler=${DC}
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2016-2019 koji-kojiro
|
||||
|
||||
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.
|
|
@ -0,0 +1,91 @@
|
|||
# matplotlib-d
|
||||
|
||||
[](LICENSE)
|
||||
[](https://travis-ci.org/koji-kojiro/matplotlib-d)
|
||||
[](https://code.dlang.org/packages/matplotlib-d)
|
||||
[](https://code.dlang.org/packages/matplotlib-d)
|
||||
|
||||
2D Plotting library for D using python and matplotlib.
|
||||
|
||||
## Requirements
|
||||
- Python
|
||||
- matplotlib
|
||||
|
||||
`matplotlib-d` uses `python3` by default, thus if you want to use `python2`, set `$MATPLOTLIB_D_PYTHON` to `python2`.
|
||||
|
||||
## Usage
|
||||
### Installation
|
||||
To use this package, put the following dependency into your project's dependencies section:
|
||||
|
||||
dub.json: `"matplotlib-d": "~>0.1.4"`
|
||||
dub.sdl: `dependency "matplotlib-d" version="~>0.1.4"`
|
||||
|
||||
|
||||
For small applications or scripts, add following sentence to the head of your script.
|
||||
```d
|
||||
#!/usr/bin/env dub
|
||||
/+ dub.sdl:
|
||||
name "name_of_your_application"
|
||||
dependency "matplotlib-d" version="~>0.1.4"
|
||||
+/
|
||||
```
|
||||
And excute with `dub run --single`.
|
||||
For more details, please refer to [the documentation of dub](https://code.dlang.org/getting_started).
|
||||
|
||||
### Syntax
|
||||
Most pyplot functions are available.
|
||||
For more details for each functions, please refer to the [documantation of pyplot](http://matplotlib.org/api/pyplot_summary.html).
|
||||
Describe Python keyword arguments as an associative array with string of keyword name as key.
|
||||
|
||||
- The Python way:
|
||||
*function(arg1, arg2..., keyword1=kwarg1, keyword2=kwarg2...)*
|
||||
- The D way:
|
||||
*function(arg1, arg2..., ["keyword1": kwarg1], ["keyword2": kwarg2])*
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Simple example:
|
||||
```d
|
||||
import std.math;
|
||||
import std.range;
|
||||
import std.algorithm;
|
||||
import plt = matplotlibd.pyplot;
|
||||
|
||||
void main() {
|
||||
auto x = iota(0, 2.05, 0.05).map!(x => x * PI);
|
||||
auto y = x.map!(sin);
|
||||
|
||||
plt.plot(x, y, "r-", ["label": "$y=sin(x)$"]);
|
||||
plt.xlim(0, 2 * PI);
|
||||
plt.ylim(-1, 1);
|
||||
plt.legend();
|
||||
plt.savefig("simple.png");
|
||||
plt.clear();
|
||||
}
|
||||
```
|
||||

|
||||
|
||||
Color plot example:
|
||||
|
||||
```d
|
||||
import std.range;
|
||||
import plt = matplotlibd.pyplot;
|
||||
|
||||
void main() {
|
||||
const n = 100;
|
||||
auto x = iota(n);
|
||||
auto y = x[];
|
||||
double[n][n] z;
|
||||
|
||||
foreach (i; 0..n)
|
||||
foreach (j; 0..n)
|
||||
z[i][j] = i + j;
|
||||
|
||||
plt.contourf(x, y, z, 64, ["cmap": "hsv"]);
|
||||
plt.colorbar();
|
||||
plt.savefig("color.png");
|
||||
plt.clear();
|
||||
}
|
||||
```
|
||||

|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "matplotlib-d",
|
||||
"authors": ["koji-kojiro"],
|
||||
"description": "2D Plotting library for D using python and matplotlib",
|
||||
"copyright": "Copyright © 2016-2019, koji-kojiro",
|
||||
"license": "MIT",
|
||||
"targetName": "matplotlibd",
|
||||
"targetType": "staticLibrary",
|
||||
"targetPath": "build",
|
||||
"workingDirectory": "build",
|
||||
"preBuildCommands": ["python3 $PACKAGE_DIR/python/prebuild.py $PACKAGE_DIR"]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
.dub
|
||||
docs.json
|
||||
__dummy.html
|
||||
*.o
|
||||
*.obj
|
||||
__test__*__
|
||||
examples
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "examples",
|
||||
"dependencies": {
|
||||
"matplotlib-d": {"version": "~master", "path": "../"}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
import std.math;
|
||||
import std.range;
|
||||
import std.random;
|
||||
import std.algorithm;
|
||||
import plt = matplotlibd.pyplot;
|
||||
|
||||
void main() {
|
||||
simple();
|
||||
color();
|
||||
polar();
|
||||
subplots();
|
||||
}
|
||||
|
||||
void bad() {
|
||||
plt.plot("hoge");
|
||||
plt.show();
|
||||
}
|
||||
|
||||
void simple() {
|
||||
auto x = iota(0, 2.05, 0.05).map!(x => x * PI);
|
||||
auto y = x.map!(sin);
|
||||
|
||||
plt.plot(x, y, "r-", ["label": "$y=sin(x)$"]);
|
||||
plt.xlim(0, 2 * PI);
|
||||
plt.ylim(-1, 1);
|
||||
plt.legend();
|
||||
plt.savefig("simple.png");
|
||||
plt.clear();
|
||||
}
|
||||
|
||||
void color() {
|
||||
const n = 100;
|
||||
auto x = iota(n);
|
||||
auto y = x[];
|
||||
double[n][n] z;
|
||||
|
||||
foreach (i; 0..n)
|
||||
foreach (j; 0..n)
|
||||
z[i][j] = i + j;
|
||||
plt.contourf(x, y, z, 64, ["cmap": "hsv"]);
|
||||
plt.colorbar();
|
||||
plt.savefig("color.png");
|
||||
plt.clear();
|
||||
}
|
||||
|
||||
void subplots() {
|
||||
auto x = iota(0, 2 * PI + 0.05, 0.05);
|
||||
|
||||
plt.subplot(221);
|
||||
plt.plot(x, x.map!(sin));
|
||||
plt.xlim(0, 2 * PI);
|
||||
plt.ylim(-1, 1);
|
||||
|
||||
plt.subplot(222);
|
||||
plt.plot(x, x.map!(cos));
|
||||
plt.xlim(0, 2 * PI);
|
||||
plt.ylim(-1, 1);
|
||||
|
||||
plt.subplot(223);
|
||||
plt.plot(x, x.map!(i => sin(i) * exp(-0.4 * i)));
|
||||
plt.xlim(0, 2 * PI);
|
||||
plt.ylim(-1, 1);
|
||||
|
||||
plt.subplot(224);
|
||||
plt.plot(x, x.map!(i => cos(i) * exp(-0.4 * i)));
|
||||
plt.xlim(0, 2 * PI);
|
||||
plt.ylim(-1, 1);
|
||||
|
||||
plt.savefig("subplots.png");
|
||||
plt.clear();
|
||||
}
|
||||
|
||||
void polar() {
|
||||
|
||||
auto r = iota(0, 1.001, 0.001);
|
||||
auto theta = r.map!(i => i * 32 * PI);
|
||||
auto area = r.map!(i => i * 2000);
|
||||
|
||||
plt.subplot(111, ["projection": "polar"]);
|
||||
plt.scatter(theta, r, ["c": r], ["s": area], ["cmap": "hsv"], ["alpha": 0.25]);
|
||||
plt.savefig("polar.png");
|
||||
plt.clear();
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
def extract_function_names(module):
|
||||
'''
|
||||
extract function names from attributes of 'module'.
|
||||
'''
|
||||
from importlib import import_module
|
||||
|
||||
mod = import_module(module.__name__)
|
||||
attr_list = dir(mod)
|
||||
scope = locals()
|
||||
|
||||
def iscallable(name):
|
||||
ignore_decorators = ['dedent','deprecated','silent_list', 'warn_deprecated']
|
||||
return eval('callable(mod.{})'.format(name), scope) and name not in ignore_decorators
|
||||
|
||||
return filter(iscallable, attr_list)
|
||||
|
||||
|
||||
def gen_pyplot_functions(dub_root):
|
||||
'''
|
||||
generate 'pyplot_functions.txt' for matplotlibd.pyplot.
|
||||
'''
|
||||
import matplotlib.pyplot
|
||||
from string import ascii_lowercase
|
||||
|
||||
functions = filter(lambda i: i[0] != '_' or i[0] in ascii_lowercase,
|
||||
extract_function_names(matplotlib.pyplot))
|
||||
|
||||
with open(dub_root + "/views/pyplot_functions.txt", "w") as f:
|
||||
f.write("\n".join(functions))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from sys import argv
|
||||
gen_pyplot_functions(argv[1])
|
|
@ -0,0 +1,26 @@
|
|||
module matplotlibd.core.pycall;
|
||||
|
||||
|
||||
void call(string py_script) {
|
||||
import std.process: environment, pipeProcess, wait, Redirect;
|
||||
|
||||
auto py_path = environment.get("MATPLOTLIB_D_PYTHON", "python3");
|
||||
auto pipes = pipeProcess(py_path, Redirect.stdin | Redirect.stderr);
|
||||
|
||||
pipes.stdin.writeln(py_script);
|
||||
pipes.stdin.writeln("exit()");
|
||||
pipes.stdin.close();
|
||||
|
||||
auto result = wait(pipes.pid);
|
||||
|
||||
if (result != 0) {
|
||||
string error;
|
||||
foreach (line; pipes.stderr.byLine)
|
||||
error ~= line ~ "\n";
|
||||
throw new Exception("\n\nERROR occurred in Python:\n" ~ error);
|
||||
}
|
||||
}
|
||||
|
||||
unittest {
|
||||
call("print(\"Passing!\")\n");
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
module matplotlibd.core.translate;
|
||||
|
||||
alias immutable bool PyBool;
|
||||
alias immutable (void*) PyNone;
|
||||
|
||||
PyBool False = false;
|
||||
PyBool True = true;
|
||||
PyNone None = null;
|
||||
|
||||
|
||||
string d2py(T)(T v) {
|
||||
import std.format: format;
|
||||
static if (is(typeof(v) : PyNone))
|
||||
return "None";
|
||||
|
||||
else static if (is(typeof(v) : bool))
|
||||
return v ? "True" : "False";
|
||||
|
||||
else static if (is(typeof(v) : string))
|
||||
return format("\"%s\"", v);
|
||||
|
||||
else
|
||||
return format("%s", v);
|
||||
}
|
||||
|
||||
unittest {
|
||||
import std.range: iota;
|
||||
assert(d2py(None) == "None");
|
||||
assert(d2py(null) == "None");
|
||||
assert(d2py(True) == "True");
|
||||
assert(d2py(true) == "True");
|
||||
assert(d2py(False) == "False");
|
||||
assert(d2py(false) == "False");
|
||||
assert(d2py("Hello!") == "\"Hello!\"");
|
||||
assert(d2py(5.iota) == "[0, 1, 2, 3, 4]");
|
||||
}
|
||||
|
||||
|
||||
string parseArgs(Args)(Args args) {
|
||||
static if (is(typeof(args.keys) : string[])) {
|
||||
string parsed;
|
||||
foreach(key; args.byKey)
|
||||
parsed ~= key ~ "=" ~ d2py(args[key]) ~ ",";
|
||||
}
|
||||
else
|
||||
string parsed = d2py(args) ~ ",";
|
||||
return parsed;
|
||||
}
|
||||
|
||||
unittest {
|
||||
import std.range: iota;
|
||||
assert(parseArgs(5) == "5,");
|
||||
assert(parseArgs(5.iota) == "[0, 1, 2, 3, 4],");
|
||||
assert(parseArgs(["test": 5]) == "test=5,");
|
||||
assert(parseArgs(["test": "test"]) == "test=\"test\",");
|
||||
assert(parseArgs(["test": 5.iota]) == "test=[0, 1, 2, 3, 4],");
|
||||
assert(parseArgs(["test": false]) == "test=False,");
|
||||
assert(parseArgs(["test": False]) == "test=False,");
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
module matplotlibd.pyplot;
|
||||
import matplotlibd.core.pycall;
|
||||
import matplotlibd.core.translate;
|
||||
|
||||
private:
|
||||
|
||||
string py_script = "import matplotlib.pyplot as plt\n";
|
||||
|
||||
immutable string plt_funcs = (){
|
||||
import std.string: splitLines;
|
||||
|
||||
string[] method_names = import("pyplot_functions.txt").splitLines;
|
||||
string plt_funcs;
|
||||
|
||||
foreach(name; method_names) {
|
||||
plt_funcs ~=
|
||||
"void " ~ name ~ "(T...)(T a)" ~
|
||||
"{import std.format: format;" ~
|
||||
"string p;if(a.length>0){foreach(i;a){p~=parseArgs(i);}" ~
|
||||
"p = p[0..$-1];}py_script~=format(\"plt."~ name ~ "(%s)\n\",p);";
|
||||
|
||||
if (name == "show" || name == "savefig")
|
||||
plt_funcs ~= "call(py_script);}\n";
|
||||
else
|
||||
plt_funcs ~= "}\n";
|
||||
}
|
||||
|
||||
return plt_funcs;
|
||||
}();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
import matplotlibd.core.translate: False, True, None;
|
||||
|
||||
|
||||
void clear() {
|
||||
py_script = "import matplotlib.pyplot as plt\n";
|
||||
}
|
||||
|
||||
mixin(plt_funcs);
|
||||
|
||||
unittest {
|
||||
import std.string;
|
||||
auto script = py_script ~ "plt.plot([1, 2],[2, 4],\"r-\",lw=2)\n";
|
||||
plot([1, 2], [2, 4], "r-", ["lw": 2]);
|
||||
assert(script == py_script);
|
||||
clear();
|
||||
assert(py_script == "import matplotlib.pyplot as plt\n");
|
||||
}
|
75
source/app.d
75
source/app.d
|
@ -3,32 +3,38 @@ import util : make, rcarray, StdArray, StdxArray, EMSIArray;
|
|||
import std.stdio : stderr, writeln;
|
||||
import std.datetime : Duration;
|
||||
|
||||
void testInsert(Container, int times = 100)()
|
||||
import std.meta : AliasSeq;
|
||||
|
||||
alias tests = AliasSeq!(testInsert, testInsertDelete, testConcat);
|
||||
alias containers = AliasSeq!(int[], StdArray!int, EMSIArray!int, rcarray!int, StdxArray!int);
|
||||
enum times = 100000;
|
||||
|
||||
void testInsert(Container, size_t size = 100)()
|
||||
{
|
||||
auto container = make!Container();
|
||||
|
||||
//debug stderr.writeln("Testing inserts on ", typeof(container).stringof);
|
||||
|
||||
foreach (i; 0 .. times)
|
||||
foreach (i; 0 .. size)
|
||||
{
|
||||
container ~= 42;
|
||||
}
|
||||
|
||||
assert(container.length == times && container[times - 1] == 42);
|
||||
assert(container.length == size && container[size - 1] == 42);
|
||||
}
|
||||
|
||||
void testInsertDelete(Container, int times = 100)()
|
||||
void testInsertDelete(Container, size_t size = 100)()
|
||||
{
|
||||
auto container = make!Container();
|
||||
|
||||
//debug stderr.writeln("Testing inserts+deletes on ", typeof(container).stringof);
|
||||
|
||||
foreach (i; 0 .. times)
|
||||
foreach (i; 0 .. size)
|
||||
{
|
||||
container ~= 42;
|
||||
}
|
||||
|
||||
foreach (i; 0 .. times)
|
||||
foreach (i; 0 .. size)
|
||||
{
|
||||
static if (is(Container : StdxArray!U, U))
|
||||
{
|
||||
|
@ -47,24 +53,33 @@ void testInsertDelete(Container, int times = 100)()
|
|||
assert(container.length == 0);
|
||||
}
|
||||
|
||||
void testConcat(Container, int times = 100)()
|
||||
void testConcat(Container, size_t size = 100)()
|
||||
{
|
||||
auto a = make!Container();
|
||||
auto b = make!Container();
|
||||
|
||||
foreach (i; 0 .. size / 2)
|
||||
{
|
||||
a ~= 1;
|
||||
b ~= 2;
|
||||
}
|
||||
|
||||
auto c = a ~ b;
|
||||
|
||||
assert(c.length == size);
|
||||
}
|
||||
|
||||
import std.meta : AliasSeq;
|
||||
alias tests = AliasSeq!(testInsert, testInsertDelete, testConcat);
|
||||
|
||||
auto testContainers(Containers...)(int times = 100000)
|
||||
auto testContainers(Containers...)()
|
||||
{
|
||||
import std.datetime.stopwatch : benchmark;
|
||||
import std.meta : staticMap;
|
||||
import std.array : array;
|
||||
|
||||
Duration[][string] results;
|
||||
|
||||
static foreach (test; tests)
|
||||
{
|
||||
results[test.stringof] = benchmark!(staticMap!(test, Containers))(times);
|
||||
results[test.stringof] = benchmark!(staticMap!(test, Containers))(times).array;
|
||||
}
|
||||
|
||||
return results;
|
||||
|
@ -84,12 +99,40 @@ void printResults(Containers...)(Duration[][string] results)
|
|||
}
|
||||
}
|
||||
|
||||
void plotResults(Containers...)(Duration[][string] results)
|
||||
{
|
||||
import plt = matplotlibd.pyplot;
|
||||
|
||||
auto i = 0;
|
||||
foreach (test, testResults; results)
|
||||
{
|
||||
import std.range : iota;
|
||||
import std.algorithm : map;
|
||||
import std.array : array;
|
||||
import std.conv : to;
|
||||
|
||||
auto title = test ~ " (" ~ times.to!string ~ " runs)";
|
||||
auto x = iota(testResults.length);
|
||||
auto height = testResults.map!(d => d.total!"msecs").array;
|
||||
|
||||
string[] names;
|
||||
foreach (Container; Containers)
|
||||
{
|
||||
names ~= Container.stringof;
|
||||
}
|
||||
|
||||
plt.subplot(results.length, 1, ++i);
|
||||
plt.bar(x, height);
|
||||
plt.xticks(x, names);
|
||||
plt.ylabel("Time (ms)");
|
||||
plt.title(title);
|
||||
}
|
||||
plt.show();
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
import std.meta : AliasSeq;
|
||||
|
||||
alias containers = AliasSeq!(int[], StdArray!int, StdxArray!int, EMSIArray!int, rcarray!int);
|
||||
|
||||
auto results = testContainers!containers;
|
||||
results.printResults!containers;
|
||||
results.plotResults!containers;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue