├── .github └── workflows │ └── continuous-integration.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── Readme.md ├── cargo_util.py ├── doc ├── Cargo.toml ├── dark.css ├── dummy.rs ├── fg.readme_example.png ├── fg1.1.png ├── gh_pages_upload.sh ├── light.css └── rustdoc.css ├── gnuplot ├── Cargo.toml ├── examples │ ├── animation_example.rs │ ├── box_and_whisker.rs │ ├── box_xy_error.rs │ ├── color.rs │ ├── color_cycling.rs │ ├── common.rs │ ├── dash_type.rs │ ├── example1.rs │ ├── example2.rs │ ├── example3.rs │ ├── example4.rs │ ├── gif.rs │ ├── inverse_api.rs │ ├── lines_3d.rs │ ├── lines_points_3d.rs │ ├── multiple_axes.rs │ ├── multiplot_options.rs │ ├── patterns.rs │ ├── points_3d.rs │ ├── polygons.rs │ ├── readme_example.rs │ ├── text.rs │ ├── time.rs │ └── variable_color.rs └── src │ ├── axes2d.rs │ ├── axes3d.rs │ ├── axes_common.rs │ ├── color.rs │ ├── coordinates.rs │ ├── datatype.rs │ ├── error_types.rs │ ├── figure.rs │ ├── lib.rs │ ├── options.rs │ ├── palettes │ ├── cm_listed.rs │ └── mod.rs │ ├── util.rs │ └── writer.rs ├── rustfmt.toml └── setup_venv.sh /.github/workflows/continuous-integration.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: 3 | push: 4 | pull_request: 5 | types: [opened, synchronize, reopened, edited] 6 | jobs: 7 | ubuntu_test: 8 | name: Ubuntu tests 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v3 13 | with: 14 | fetch-depth: 1 15 | - name: Install Rust 16 | run: | 17 | rustup toolchain install nightly 18 | rustup default nightly 19 | rustup component add rustfmt --toolchain nightly-x86_64-unknown-linux-gnu 20 | - name: Setup 21 | run: | 22 | curl -LsSf https://astral.sh/uv/install.sh | sh 23 | . setup_venv.sh 24 | sudo apt-get install gnuplot 25 | - name: Tests 26 | run: | 27 | . venv/bin/activate 28 | ./cargo_util.py --test 29 | ./gnuplot/target/debug/examples/example1 --no-show 30 | ./gnuplot/target/debug/examples/example2 --no-show 31 | ./gnuplot/target/debug/examples/example3 --no-show 32 | ./gnuplot/target/debug/examples/example4 --no-show 33 | 34 | if [ -n "${{ github.base_ref }}" ]; then 35 | CHANGED_OUTPUTS=$(echo "${{ github.event.pull_request.body }}" | sed -n 's/.*CHANGED_OUTPUTS=\([^ ]*\).*/\1/p') 36 | BASE_REF="${{ github.base_ref }}" 37 | HEAD_REF=$(git rev-parse HEAD) 38 | echo "CHANGED_OUTPUTS: $CHANGED_OUTPUTS" 39 | 40 | git fetch origin $BASE_REF 41 | git checkout $BASE_REF 42 | ./cargo_util.py --make_golden_outputs 43 | git checkout $HEAD_REF 44 | ./cargo_util.py --test_outputs --ignore_new_outputs --changed_outputs=$CHANGED_OUTPUTS 45 | fi 46 | - name: Upload golden outputs 47 | if: ${{ always() }} 48 | uses: actions/upload-artifact@v4 49 | with: 50 | name: golden_outputs 51 | path: golden_outputs 52 | - name: Upload test outputs 53 | if: ${{ always() }} 54 | uses: actions/upload-artifact@v4 55 | with: 56 | name: test_outputs 57 | path: test_outputs 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | target 3 | Cargo.lock 4 | gnuplot/*.png 5 | gnuplot/*.gif 6 | gnuplot/*.pdf 7 | gnuplot/*.gnuplot 8 | /*.png 9 | /*.gif 10 | /*.pdf 11 | /*.gnuplot 12 | .idea 13 | venv 14 | golden_outputs 15 | test_outputs 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Style 2 | 3 | Please run `cargo fmt` before sending pull requests. 4 | 5 | # Output tests 6 | 7 | The CI verifies that the PNG outputs do not unexpectedly change for existing 8 | examples. This is done by checking out the repository before your PR and after 9 | the PR and comparing the outputs. If you changed some examples deliberately, 10 | you can indicate this in the PR description by adding a line like: 11 | 12 | ``` 13 | CHANGED_OUTPUTS=image1.png,image2.png 14 | ``` 15 | 16 | where `image1` etc is derived from the string you pass to the `c.show(&mut fg, 17 | "image1");` line in the example. To run the tests manually you run these two 18 | commands (requires [uv](https://github.com/astral-sh/uv) to be installed): 19 | 20 | ```bash 21 | source setup_venv.sh # Do this once 22 | . venv/bin/activate # Do this if you already set up venv 23 | ./cargo_util.py --make_golden_outputs # On the base commit (typically master) 24 | ./cargo_util.py --test_outputs --ignore_new_outputs --changed_outputs=image1.png,image2.png # With your changes applied 25 | ``` 26 | 27 | We don't check in the golden outputs because gnuplot does not guarantee 28 | cross-platform pixel-perfect outputs, so the outputs end up being specific to 29 | the platform they're generated on. Thus, we only compare two commits instead on 30 | the same platform (i.e. your local machine, or the CI runner). 31 | 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # RustGnuplot 2 | 3 | A Gnuplot controller written in Rust. 4 | 5 | ![Build Status](https://github.com/SiegeLord/RustGnuplot/actions/workflows/continuous-integration.yml/badge.svg) 6 | [![](https://img.shields.io/crates/v/gnuplot.svg)](https://crates.io/crates/gnuplot) 7 | 8 | ## Documentation 9 | 10 | On [docs.rs](https://docs.rs/gnuplot/latest/gnuplot/) 11 | 12 | ## Examples 13 | 14 | A simple example: 15 | 16 | ```rust 17 | let mut fg = Figure::new(); 18 | fg.axes2d() 19 | .set_title("A plot", &[]) 20 | .set_legend(Graph(0.5), Graph(0.9), &[], &[]) 21 | .set_x_label("x", &[]) 22 | .set_y_label("y^2", &[]) 23 | .lines( 24 | &[-3., -2., -1., 0., 1., 2., 3.], 25 | &[9., 4., 1., 0., 1., 4., 9.], 26 | &[Caption("Parabola")], 27 | ); 28 | fg.show().unwrap(); 29 | ``` 30 | 31 | ![Simple example plot](doc/fg.readme_example.png) 32 | 33 | A somewhat involved 2D example (see `example1.rs` in the `examples` directory): 34 | 35 | ![Complicated example plot](doc/fg1.1.png) 36 | 37 | ## Features 38 | 39 | * Simple 2D plots 40 | * lines 41 | * points 42 | * points + lines 43 | * error bars 44 | * ...and more! 45 | * Simple 3D plots 46 | * surface plots 47 | * heatmaps 48 | * contours 49 | 50 | ## Building 51 | 52 | ### Via Cargo 53 | 54 | ``` 55 | cargo build 56 | ``` 57 | -------------------------------------------------------------------------------- /cargo_util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import fileinput 5 | import re 6 | import os 7 | import glob 8 | import time 9 | import toml 10 | import json 11 | import pathlib 12 | from shutil import copy, rmtree 13 | from subprocess import check_call, check_output, CalledProcessError 14 | 15 | def split(s): 16 | ret = s.split('\n') 17 | return filter(lambda v: v, ret) 18 | 19 | crate_list=split(""" 20 | gnuplot 21 | """) 22 | 23 | parser = argparse.ArgumentParser(description='Perform an operation on all crates.') 24 | parser.add_argument('--version', metavar='VERSION', default='', help='set the version to VERSION') 25 | parser.add_argument('--publish', action='store_true', help='publish the crates') 26 | parser.add_argument('--build', action='store_true', help='build the crates') 27 | parser.add_argument('--test', action='store_true', help='test the crates') 28 | parser.add_argument('--make_golden_outputs', action='store_true', help='make the golden outputs') 29 | parser.add_argument('--test_outputs', action='store_true', help='run the output tests') 30 | parser.add_argument('--ignore_new_outputs', action='store_true', help='whether to ignore new outputs') 31 | parser.add_argument('--changed_outputs', type=str, default='', help='comma separated list of outputs to ignore failures in, e.g. "foo.png,bar.png"') 32 | parser.add_argument('--clean', action='store_true', help='clean the crates') 33 | parser.add_argument('--doc', action='store_true', help='build the documentation') 34 | parser.add_argument('--format', action='store_true', help='format all the non-sys crates') 35 | parser.add_argument('--verbose', action='store_true', help='pass --verbose to cargo') 36 | parser.add_argument('--num_retries', type=float, default=5, help='number of retries when publishing') 37 | 38 | args = parser.parse_args() 39 | 40 | def cargo_cmd(*command): 41 | return ['cargo'] + list(command) + (['--verbose'] if args.verbose else []) 42 | 43 | if len(args.version) > 0: 44 | crates_and_doc = ['doc'] 45 | crates_and_doc.extend(crate_list) 46 | 47 | for crate in crates_and_doc: 48 | cargo_toml = crate + '/Cargo.toml' 49 | print('Processing', cargo_toml) 50 | 51 | for line in fileinput.input(cargo_toml, inplace=1): 52 | line = re.sub('version = "(=?).*" #auto', r'version = "\g<1>' + args.version + '" #auto', line) 53 | print(line, end='') 54 | 55 | if args.publish: 56 | for crate in crate_list: 57 | print('Publishing crate inside', crate) 58 | metadata = json.loads( 59 | check_output( 60 | 'cargo metadata --format-version=1 --no-deps'.split(' '), 61 | cwd=crate, 62 | ) 63 | ) 64 | 65 | package_metadata = metadata['packages'][0] 66 | new_version = package_metadata['version'] 67 | crate_name = package_metadata['name'] 68 | 69 | search_output = check_output( 70 | f'cargo search {crate_name} --limit 9999'.split(' ') 71 | ).decode('utf8') 72 | 73 | search_result = toml.loads(search_output) 74 | old_version = search_result[crate_name] 75 | if old_version == new_version: 76 | print(f'Version {new_version} already published, skipping.') 77 | continue 78 | 79 | for i in range(args.num_retries): 80 | try: 81 | check_call(cargo_cmd('publish'), cwd=crate) 82 | break 83 | except CalledProcessError: 84 | print(f'Try {i} failed') 85 | time.sleep(1. + i) 86 | 87 | if args.build: 88 | for crate in crate_list: 89 | check_call(cargo_cmd('build'), cwd=crate) 90 | 91 | if args.format: 92 | for crate in crate_list: 93 | check_call(cargo_cmd('fmt'), cwd=crate) 94 | 95 | if args.test: 96 | crates_no_examples = filter(lambda crate: crate != 'examples', crate_list) 97 | for crate in crates_no_examples: 98 | check_call(cargo_cmd('test'), cwd=crate) 99 | check_call(cargo_cmd('fmt', '--check'), cwd=crate) 100 | 101 | if args.test_outputs or args.make_golden_outputs: 102 | import numpy as np 103 | from PIL import Image 104 | 105 | if args.test_outputs: 106 | output_dir = 'test_outputs' 107 | else: 108 | output_dir = 'golden_outputs' 109 | os.makedirs(output_dir, exist_ok=True) 110 | output_dir = os.path.abspath(output_dir) 111 | metadata = json.loads(check_output(cargo_cmd('metadata', '--format-version=1', '--no-deps'), cwd='gnuplot').decode('utf8')) 112 | for target in metadata['packages'][0]['targets']: 113 | if target['kind'] != ['example']: 114 | continue 115 | 116 | if target['name'] in [ 117 | 'animation_example', # Special. 118 | 'inverse_api', # Special. 119 | 'example3', # Broken. 120 | ]: 121 | continue 122 | 123 | check_call(cargo_cmd('run', '--example', target['name'], '--', '--no-show', '--output-dir', output_dir, '--save-png'), cwd='gnuplot') 124 | 125 | if args.make_golden_outputs: 126 | exit(0) 127 | 128 | golden_images = [pathlib.Path(f) for f in glob.glob('golden_outputs/*.png')] 129 | test_images = [pathlib.Path(f) for f in glob.glob(f'{output_dir}/*.png')] 130 | 131 | golden_filenames = set(f.name for f in golden_images) 132 | test_filenames = set(f.name for f in test_images) 133 | if golden_filenames != test_filenames: 134 | missing = set(golden_filenames) - set(test_filenames) 135 | extra = set(test_filenames) - set(golden_filenames) 136 | if not args.ignore_new_outputs or missing: 137 | assert False, f"Test images don't match golden images.\nExtra: {extra}\nMissing: {missing}" 138 | 139 | changed_outputs = args.changed_outputs.split(',') 140 | failed = False 141 | for image_name in golden_images: 142 | golden_image_path = pathlib.Path(image_name) 143 | test_image_path = pathlib.Path(output_dir) / golden_image_path.name 144 | assert test_image_path.exists(), f"{test_image_path} not found" 145 | if golden_image_path.name in changed_outputs: 146 | continue 147 | golden_image = np.array(Image.open(golden_image_path)).astype(np.float32) 148 | test_image = np.array(Image.open(test_image_path)).astype(np.float32) 149 | try: 150 | np.testing.assert_allclose(golden_image, test_image, atol=5, err_msg=f"{golden_image_path.resolve()}\n{test_image_path.resolve()}") 151 | except AssertionError as e: 152 | failed = True 153 | print(e) 154 | if failed: 155 | exit(1) 156 | 157 | 158 | if args.clean: 159 | crates_and_doc = ['doc'] 160 | crates_and_doc.extend(crate_list) 161 | for crate in crates_and_doc: 162 | print('Cleaning', crate) 163 | lock = crate + '/Cargo.lock' 164 | if os.path.exists(lock): 165 | os.remove(lock) 166 | check_call(cargo_cmd('clean'), cwd=crate) 167 | 168 | if args.doc: 169 | rmtree('doc/target/doc', ignore_errors=True) 170 | print('Building docs') 171 | check_call(['cargo', 'doc'], cwd='doc') 172 | print('Fixing up the search index') 173 | found = False 174 | for line in fileinput.input('doc/target/doc/search-index.js', inplace=1): 175 | new_line = re.sub(r'"delete_me".*', r'\\', line) 176 | if new_line != line: 177 | found = True 178 | else: 179 | print(new_line, end='') 180 | if not found: 181 | raise Exception("Couldn't find the line in search-index.js!") 182 | found = False 183 | for line in fileinput.input('doc/target/doc/source-files.js', inplace=1): 184 | new_line = re.sub(r'sourcesIndex\["delete_me"\].*', r'', line) 185 | if new_line != line: 186 | found = True 187 | else: 188 | print(new_line, end='') 189 | if not found: 190 | raise Exception("Couldn't find the line in source-files.js!") 191 | print('Copying new CSS') 192 | copy('doc/rustdoc.css', 'doc/target/doc/rustdoc.css') 193 | copy('doc/light.css', 'doc/target/doc/light.css') 194 | copy('doc/dark.css', 'doc/target/doc/dark.css') 195 | -------------------------------------------------------------------------------- /doc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "doc" 4 | version = "0.0.46" #auto 5 | authors = [ "SiegeLord " ] 6 | 7 | [lib] 8 | name = "delete_me" 9 | path = "dummy.rs" 10 | 11 | [dependencies.gnuplot] 12 | 13 | path = "../gnuplot" 14 | version = "=0.0.46" #auto 15 | -------------------------------------------------------------------------------- /doc/dark.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 The Rust Project Developers. See the COPYRIGHT 3 | * file at the top-level directory of this distribution and at 4 | * http://rust-lang.org/COPYRIGHT. 5 | * 6 | * Licensed under the Apache License, Version 2.0 or the MIT license 8 | * , at your 9 | * option. This file may not be copied, modified, or distributed 10 | * except according to those terms. 11 | */ 12 | 13 | /* General structure and fonts */ 14 | 15 | body { 16 | background-color: #000030; 17 | color: black; 18 | } 19 | 20 | h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { 21 | color: black; 22 | } 23 | h1.fqn { 24 | border-bottom-color: #D5D5D5; 25 | } 26 | h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { 27 | border-bottom-color: #DDDDDD; 28 | } 29 | h1.fqn { 30 | font-size: 20pt; 31 | font-weight: normal; 32 | } 33 | 34 | /* 35 | .in-band { 36 | background-color: white; 37 | } 38 | */ 39 | 40 | .invisible { 41 | background: rgba(0, 0, 0, 0); 42 | } 43 | 44 | pre { 45 | background-color: #F5F5F5; 46 | } 47 | 48 | .sidebar { 49 | background-color: #F1F1F1; 50 | } 51 | 52 | .sidebar .current { 53 | background-color: #FDFFD3; 54 | } 55 | 56 | .source .sidebar { 57 | background-color: #fff; 58 | } 59 | 60 | .sidebar .version { 61 | border-bottom-color: #DDD; 62 | } 63 | 64 | #sidebar-toggle { 65 | background-color: #F1F1F1; 66 | } 67 | #sidebar-toggle:hover { 68 | background-color: #E0E0E0; 69 | } 70 | #source-sidebar { 71 | background-color: #F1F1F1; 72 | } 73 | #source-sidebar>.title { 74 | border-bottom-color: #ccc; 75 | } 76 | 77 | a[href].sidebar-title { 78 | background-color: #000030; 79 | background-image: linear-gradient( #000030, #000090 ); 80 | border: 0px; 81 | margin: 0px; 82 | color: white; 83 | font-weight: bold; 84 | } 85 | 86 | a:hover[href].sidebar-title { 87 | background-color: #000030; 88 | background-image: linear-gradient( #000030, #000090 ); 89 | text-shadow: 0 0 0.25em #EEEEEC; 90 | border: 0px; 91 | margin: 0px; 92 | color: white; 93 | font-weight: bold; 94 | } 95 | 96 | .block a:hover { 97 | background: #F5F5F5; 98 | } 99 | 100 | .line-numbers span { color: #c67e2d; } 101 | .line-numbers .line-highlighted { 102 | background-color: #f6fdb0 !important; 103 | } 104 | 105 | .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { 106 | border-bottom-color: #DDD; 107 | } 108 | 109 | .docblock table { 110 | border-color: #ddd; 111 | } 112 | 113 | .docblock table td { 114 | border-top-color: #ddd; 115 | border-bottom-color: #ddd; 116 | } 117 | 118 | .docblock table th { 119 | border-top-color: #ddd; 120 | border-bottom-color: #ddd; 121 | } 122 | 123 | :target { background: #FDFFD3; } 124 | 125 | :target > .in-band { 126 | background: #FDFFD3; 127 | } 128 | 129 | .content { 130 | background: #E1E1E1; 131 | } 132 | 133 | .content .method .where, 134 | .content .fn .where, 135 | .content .where.fmt-newline { 136 | color: #4E4C4C; 137 | } 138 | 139 | .content h1.fqn, .content > h2, .content > h3 { 140 | background-color: #000030; 141 | background-image: linear-gradient( #000030, #000090 ); 142 | color: #FFFFFF; 143 | padding: 6pt; 144 | } 145 | 146 | .content h1.fqn a:hover[href], .content > h2 a:hover[href] { 147 | text-shadow: 0 0 0.25em #EEEEEC; 148 | border: 0px; 149 | margin: 0px; 150 | } 151 | 152 | .content h1.fqn a, .content > h2 a { 153 | color: #FCFCFC 154 | } 155 | 156 | .content h1 { 157 | padding-left: 10px; 158 | margin-top: 0; 159 | font-weight: bold; 160 | } 161 | 162 | .content .highlighted { 163 | color: #000 !important; 164 | background-color: #ccc; 165 | } 166 | .content .highlighted a, .content .highlighted span { color: #000 !important; } 167 | .content .highlighted.trait { background-color: #c7b6ff; } 168 | .content .highlighted.mod, 169 | .content .highlighted.externcrate { background-color: #afc6e4; } 170 | .content .highlighted.enum { background-color: #b4d1b9; } 171 | .content .highlighted.struct { background-color: #e7b1a0; } 172 | .content .highlighted.union { background-color: #b7bd49; } 173 | .content .highlighted.fn, 174 | .content .highlighted.method, 175 | .content .highlighted.tymethod { background-color: #c6afb3; } 176 | .content .highlighted.type { background-color: #ffc891; } 177 | .content .highlighted.foreigntype { background-color: #f5c4ff; } 178 | .content .highlighted.macro { background-color: #8ce488; } 179 | .content .highlighted.constant, 180 | .content .highlighted.static { background-color: #c3e0ff; } 181 | .content .highlighted.primitive { background-color: #9aecff; } 182 | 183 | .content span.enum, .content a.enum, .block a.current.enum { color: #508157; } 184 | .content span.struct, .content a.struct, .block a.current.struct { color: #ad448e; !important } 185 | .content span.type, .content a.type, .block a.current.type { color: #ba5d00; } 186 | .content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #cd00e2; } 187 | .content span.macro, .content a.macro, .block a.current.macro { color: #068000; } 188 | .content span.union, .content a.union, .block a.current.union { color: #767b27; } 189 | .content span.constant, .content a.constant, .block a.current.constant, 190 | .content span.static, .content a.static, .block a.current.static { color: #546e8a; } 191 | .content span.primitive, .content a.primitive, .block a.current.primitive { color: #2c8093; } 192 | .content span.externcrate, 193 | .content span.mod, .content a.mod, .block a.current.mod { color: #4d76ae; } 194 | .content span.trait, .content a.trait, .block a.current.trait { color: #7c5af3; } 195 | .content span.fn, .content a.fn, .block a.current.fn, 196 | .content span.method, .content a.method, .block a.current.method, 197 | .content span.tymethod, .content a.tymethod, .block a.current.tymethod, 198 | .content .fnname { color: #9a6e31; } 199 | 200 | pre.rust .comment { color: #8E908C; } 201 | pre.rust .doccomment { color: #4D4D4C; } 202 | 203 | nav { 204 | border-bottom-color: #e0e0e0; 205 | } 206 | nav.main .current { 207 | border-top-color: #000; 208 | border-bottom-color: #000; 209 | } 210 | nav.main .separator { 211 | border: 1px solid #000; 212 | } 213 | a { 214 | color: #000; 215 | } 216 | 217 | .docblock a, .docblock-short a, .stability a { 218 | color: #3873AD; 219 | } 220 | 221 | a[href] { 222 | text-decoration: none; 223 | color: #1D23A5; 224 | } 225 | 226 | a:hover[href] { 227 | border: 1px dotted #000000; 228 | margin: -1px -1px -1px -1px; 229 | } 230 | 231 | nav.sidebar > a:hover[href] { 232 | border: 0; 233 | margin: 0 0 0 0; 234 | } 235 | 236 | a.test-arrow { 237 | color: #f5f5f5; 238 | } 239 | 240 | .collapse-toggle { 241 | color: #999; 242 | } 243 | 244 | .search-input { 245 | color: #555; 246 | box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; 247 | background-color: white; 248 | } 249 | 250 | .search-input:focus { 251 | border-color: #66afe9; 252 | } 253 | 254 | .stab.unstable { background: #FFF5D6; border-color: #FFC600; } 255 | .stab.deprecated { background: #F3DFFF; border-color: #7F0087; } 256 | .stab.portability { background: #C4ECFF; border-color: #7BA5DB; } 257 | 258 | .module-item .stab { 259 | color: #000; 260 | } 261 | 262 | #help > div { 263 | background: #e9e9e9; 264 | border-color: #bfbfbf; 265 | } 266 | 267 | .since { 268 | color: grey; 269 | } 270 | 271 | tr.result span.primitive::after { 272 | color: black; 273 | } 274 | 275 | .line-numbers :target { background-color: transparent; } 276 | 277 | /* Code highlighting */ 278 | pre.rust .kw { color: #8959A8; } 279 | pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; } 280 | pre.rust .number, pre.rust .string { color: #718C00; } 281 | pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, 282 | pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; } 283 | pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } 284 | pre.rust .lifetime { color: #B76514; } 285 | pre.rust .question-mark { 286 | color: #ff9011; 287 | } 288 | 289 | a.test-arrow { 290 | background-color: rgba(78, 139, 202, 0.2); 291 | } 292 | 293 | a.test-arrow:hover{ 294 | background-color: #4e8bca; 295 | } 296 | 297 | .toggle-label { 298 | color: #999; 299 | } 300 | 301 | :target > code { 302 | background: #FDFFD3; 303 | } 304 | 305 | pre.compile_fail { 306 | border-left: 2px solid rgba(255,0,0,.4); 307 | } 308 | 309 | pre.compile_fail:hover, .information:hover + pre.compile_fail { 310 | border-left: 2px solid #f00; 311 | } 312 | 313 | pre.ignore { 314 | border-left: 2px solid rgba(255,142,0,.4); 315 | } 316 | 317 | pre.ignore:hover, .information:hover + pre.ignore { 318 | border-left: 2px solid #ff9200; 319 | } 320 | 321 | .tooltip.compile_fail { 322 | color: rgba(255,0,0,.3); 323 | } 324 | 325 | .information > .compile_fail:hover { 326 | color: #f00; 327 | } 328 | 329 | .tooltip.ignore { 330 | color: rgba(255,142,0,.3); 331 | } 332 | 333 | .information > .ignore:hover { 334 | color: rgba(255,142,0,1); 335 | } 336 | 337 | .search-failed > a { 338 | color: #0089ff; 339 | } 340 | 341 | .tooltip .tooltiptext { 342 | background-color: black; 343 | color: #fff; 344 | } 345 | 346 | .tooltip .tooltiptext::after { 347 | border-color: transparent black transparent transparent; 348 | } 349 | 350 | .important-traits .tooltip .tooltiptext { 351 | background-color: white; 352 | color: black; 353 | border-color: black; 354 | } 355 | 356 | #titles > div { 357 | border-bottom-color: #ccc; 358 | } 359 | 360 | #titles > div.selected { 361 | border-bottom-color: #0078ee; 362 | } 363 | 364 | #titles > div:hover { 365 | border-bottom-color: #0089ff; 366 | } 367 | 368 | #titles > div > div.count { 369 | color: #888; 370 | } 371 | 372 | .modal { 373 | background-color: rgba(0,0,0,0.3); 374 | } 375 | 376 | .modal-content { 377 | background-color: #eee; 378 | border-color: #999; 379 | } 380 | 381 | .modal-content > .close { 382 | background-color: #eee; 383 | border-color: #999; 384 | } 385 | 386 | .modal-content > .close:hover { 387 | background-color: #ff1f1f; 388 | color: white; 389 | } 390 | 391 | .modal-content > .whiter { 392 | background-color: #eee; 393 | } 394 | 395 | .modal-content > .close:hover + .whiter { 396 | background-color: #ff1f1f; 397 | } 398 | 399 | @media (max-width: 700px) { 400 | .sidebar-menu { 401 | background-color: #F1F1F1; 402 | border-bottom-color: #e0e0e0; 403 | border-right-color: #e0e0e0; 404 | } 405 | 406 | .sidebar-elems { 407 | background-color: #F1F1F1; 408 | border-right-color: #000; 409 | } 410 | 411 | #sidebar-filler { 412 | background-color: #F1F1F1; 413 | border-bottom-color: #e0e0e0; 414 | } 415 | } 416 | 417 | kbd { 418 | color: #000; 419 | background-color: #fafbfc; 420 | border-color: #d1d5da; 421 | border-bottom-color: #c6cbd1; 422 | box-shadow-color: #c6cbd1; 423 | } 424 | 425 | #theme-picker, #settings-menu { 426 | border-color: #e0e0e0; 427 | background-color: #fff; 428 | } 429 | 430 | #theme-picker:hover, #theme-picker:focus, 431 | #settings-menu:hover, #settings-menu:focus { 432 | border-color: #717171; 433 | } 434 | 435 | #theme-choices { 436 | border-color: #ccc; 437 | background-color: #fff; 438 | } 439 | 440 | #theme-choices > button:not(:first-child) { 441 | border-top-color: #e0e0e0; 442 | } 443 | 444 | #theme-choices > button:hover, #theme-choices > button:focus { 445 | background-color: #eee; 446 | } 447 | 448 | @media (max-width: 700px) { 449 | #theme-picker { 450 | background: #fff; 451 | } 452 | } 453 | 454 | #all-types { 455 | background-color: #fff; 456 | } 457 | #all-types:hover { 458 | background-color: #f9f9f9; 459 | } 460 | -------------------------------------------------------------------------------- /doc/dummy.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /doc/fg.readme_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SiegeLord/RustGnuplot/8a1dde97369dbfeea66698d8f2dd20f2a47ac7d1/doc/fg.readme_example.png -------------------------------------------------------------------------------- /doc/fg1.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SiegeLord/RustGnuplot/8a1dde97369dbfeea66698d8f2dd20f2a47ac7d1/doc/fg1.1.png -------------------------------------------------------------------------------- /doc/gh_pages_upload.sh: -------------------------------------------------------------------------------- 1 | if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then 2 | echo Starting gh-pages upload... 3 | 4 | cp -r doc $HOME/doc 5 | 6 | # Go to home and setup git 7 | cd $HOME 8 | git config --global user.email "travis@travis-ci.org" 9 | git config --global user.name "Travis" 10 | 11 | # Clone gh-pages branch 12 | git clone --quiet --branch=gh-pages https://${GH_TOKEN}@github.com/SiegeLord/RustGnuplot.git gh-pages > /dev/null 13 | 14 | # Copy over the documentation 15 | cd gh-pages 16 | rm -rf doc 17 | cp -r $HOME/doc . 18 | 19 | # Add, commit and push files 20 | git add -f --all . 21 | git commit -m "Update docs from Travis build $TRAVIS_BUILD_NUMBER" 22 | git push -fq origin gh-pages > /dev/null 23 | 24 | echo Done uploading documentation to gh-pages! 25 | fi 26 | -------------------------------------------------------------------------------- /doc/light.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 The Rust Project Developers. See the COPYRIGHT 3 | * file at the top-level directory of this distribution and at 4 | * http://rust-lang.org/COPYRIGHT. 5 | * 6 | * Licensed under the Apache License, Version 2.0 or the MIT license 8 | * , at your 9 | * option. This file may not be copied, modified, or distributed 10 | * except according to those terms. 11 | */ 12 | 13 | /* General structure and fonts */ 14 | 15 | body { 16 | background-color: #000030; 17 | color: black; 18 | } 19 | 20 | h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { 21 | color: black; 22 | } 23 | h1.fqn { 24 | border-bottom-color: #D5D5D5; 25 | } 26 | h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { 27 | border-bottom-color: #DDDDDD; 28 | } 29 | h1.fqn { 30 | font-size: 20pt; 31 | font-weight: normal; 32 | } 33 | 34 | /* 35 | .in-band { 36 | background-color: white; 37 | } 38 | */ 39 | 40 | .invisible { 41 | background: rgba(0, 0, 0, 0); 42 | } 43 | 44 | pre { 45 | background-color: #F5F5F5; 46 | } 47 | 48 | .sidebar { 49 | background-color: #F1F1F1; 50 | } 51 | 52 | .sidebar .current { 53 | background-color: #FDFFD3; 54 | } 55 | 56 | .source .sidebar { 57 | background-color: #fff; 58 | } 59 | 60 | .sidebar .version { 61 | border-bottom-color: #DDD; 62 | } 63 | 64 | #sidebar-toggle { 65 | background-color: #F1F1F1; 66 | } 67 | #sidebar-toggle:hover { 68 | background-color: #E0E0E0; 69 | } 70 | #source-sidebar { 71 | background-color: #F1F1F1; 72 | } 73 | #source-sidebar>.title { 74 | border-bottom-color: #ccc; 75 | } 76 | 77 | a[href].sidebar-title { 78 | background-color: #000030; 79 | background-image: linear-gradient( #000030, #000090 ); 80 | border: 0px; 81 | margin: 0px; 82 | color: white; 83 | font-weight: bold; 84 | } 85 | 86 | a:hover[href].sidebar-title { 87 | background-color: #000030; 88 | background-image: linear-gradient( #000030, #000090 ); 89 | text-shadow: 0 0 0.25em #EEEEEC; 90 | border: 0px; 91 | margin: 0px; 92 | color: white; 93 | font-weight: bold; 94 | } 95 | 96 | .block a:hover { 97 | background: #F5F5F5; 98 | } 99 | 100 | .line-numbers span { color: #c67e2d; } 101 | .line-numbers .line-highlighted { 102 | background-color: #f6fdb0 !important; 103 | } 104 | 105 | .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { 106 | border-bottom-color: #DDD; 107 | } 108 | 109 | .docblock table { 110 | border-color: #ddd; 111 | } 112 | 113 | .docblock table td { 114 | border-top-color: #ddd; 115 | border-bottom-color: #ddd; 116 | } 117 | 118 | .docblock table th { 119 | border-top-color: #ddd; 120 | border-bottom-color: #ddd; 121 | } 122 | 123 | :target { background: #FDFFD3; } 124 | 125 | :target > .in-band { 126 | background: #FDFFD3; 127 | } 128 | 129 | .content { 130 | background: #E1E1E1; 131 | } 132 | 133 | .content .method .where, 134 | .content .fn .where, 135 | .content .where.fmt-newline { 136 | color: #4E4C4C; 137 | } 138 | 139 | .content h1.fqn, .content > h2, .content > h3 { 140 | background-color: #000030; 141 | background-image: linear-gradient( #000030, #000090 ); 142 | color: #FFFFFF; 143 | padding: 6pt; 144 | } 145 | 146 | .content h1.fqn a:hover[href], .content > h2 a:hover[href] { 147 | text-shadow: 0 0 0.25em #EEEEEC; 148 | border: 0px; 149 | margin: 0px; 150 | } 151 | 152 | .content h1.fqn a, .content > h2 a { 153 | color: #FCFCFC 154 | } 155 | 156 | .content h1 { 157 | padding-left: 10px; 158 | margin-top: 0; 159 | font-weight: bold; 160 | } 161 | 162 | .content .highlighted { 163 | color: #000 !important; 164 | background-color: #ccc; 165 | } 166 | .content .highlighted a, .content .highlighted span { color: #000 !important; } 167 | .content .highlighted.trait { background-color: #c7b6ff; } 168 | .content .highlighted.mod, 169 | .content .highlighted.externcrate { background-color: #afc6e4; } 170 | .content .highlighted.enum { background-color: #b4d1b9; } 171 | .content .highlighted.struct { background-color: #e7b1a0; } 172 | .content .highlighted.union { background-color: #b7bd49; } 173 | .content .highlighted.fn, 174 | .content .highlighted.method, 175 | .content .highlighted.tymethod { background-color: #c6afb3; } 176 | .content .highlighted.type { background-color: #ffc891; } 177 | .content .highlighted.foreigntype { background-color: #f5c4ff; } 178 | .content .highlighted.macro { background-color: #8ce488; } 179 | .content .highlighted.constant, 180 | .content .highlighted.static { background-color: #c3e0ff; } 181 | .content .highlighted.primitive { background-color: #9aecff; } 182 | 183 | .content span.enum, .content a.enum, .block a.current.enum { color: #508157; } 184 | .content span.struct, .content a.struct, .block a.current.struct { color: #ad448e; !important } 185 | .content span.type, .content a.type, .block a.current.type { color: #ba5d00; } 186 | .content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #cd00e2; } 187 | .content span.macro, .content a.macro, .block a.current.macro { color: #068000; } 188 | .content span.union, .content a.union, .block a.current.union { color: #767b27; } 189 | .content span.constant, .content a.constant, .block a.current.constant, 190 | .content span.static, .content a.static, .block a.current.static { color: #546e8a; } 191 | .content span.primitive, .content a.primitive, .block a.current.primitive { color: #2c8093; } 192 | .content span.externcrate, 193 | .content span.mod, .content a.mod, .block a.current.mod { color: #4d76ae; } 194 | .content span.trait, .content a.trait, .block a.current.trait { color: #7c5af3; } 195 | .content span.fn, .content a.fn, .block a.current.fn, 196 | .content span.method, .content a.method, .block a.current.method, 197 | .content span.tymethod, .content a.tymethod, .block a.current.tymethod, 198 | .content .fnname { color: #9a6e31; } 199 | 200 | pre.rust .comment { color: #8E908C; } 201 | pre.rust .doccomment { color: #4D4D4C; } 202 | 203 | nav { 204 | border-bottom-color: #e0e0e0; 205 | } 206 | nav.main .current { 207 | border-top-color: #000; 208 | border-bottom-color: #000; 209 | } 210 | nav.main .separator { 211 | border: 1px solid #000; 212 | } 213 | a { 214 | color: #000; 215 | } 216 | 217 | .docblock a, .docblock-short a, .stability a { 218 | color: #3873AD; 219 | } 220 | 221 | a[href] { 222 | text-decoration: none; 223 | color: #1D23A5; 224 | } 225 | 226 | a:hover[href] { 227 | border: 1px dotted #000000; 228 | margin: -1px -1px -1px -1px; 229 | } 230 | 231 | nav.sidebar > a:hover[href] { 232 | border: 0; 233 | margin: 0 0 0 0; 234 | } 235 | 236 | a.test-arrow { 237 | color: #f5f5f5; 238 | } 239 | 240 | .collapse-toggle { 241 | color: #999; 242 | } 243 | 244 | .search-input { 245 | color: #555; 246 | box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; 247 | background-color: white; 248 | } 249 | 250 | .search-input:focus { 251 | border-color: #66afe9; 252 | } 253 | 254 | .stab.unstable { background: #FFF5D6; border-color: #FFC600; } 255 | .stab.deprecated { background: #F3DFFF; border-color: #7F0087; } 256 | .stab.portability { background: #C4ECFF; border-color: #7BA5DB; } 257 | 258 | .module-item .stab { 259 | color: #000; 260 | } 261 | 262 | #help > div { 263 | background: #e9e9e9; 264 | border-color: #bfbfbf; 265 | } 266 | 267 | .since { 268 | color: grey; 269 | } 270 | 271 | tr.result span.primitive::after { 272 | color: black; 273 | } 274 | 275 | .line-numbers :target { background-color: transparent; } 276 | 277 | /* Code highlighting */ 278 | pre.rust .kw { color: #8959A8; } 279 | pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; } 280 | pre.rust .number, pre.rust .string { color: #718C00; } 281 | pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, 282 | pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; } 283 | pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } 284 | pre.rust .lifetime { color: #B76514; } 285 | pre.rust .question-mark { 286 | color: #ff9011; 287 | } 288 | 289 | a.test-arrow { 290 | background-color: rgba(78, 139, 202, 0.2); 291 | } 292 | 293 | a.test-arrow:hover{ 294 | background-color: #4e8bca; 295 | } 296 | 297 | .toggle-label { 298 | color: #999; 299 | } 300 | 301 | :target > code { 302 | background: #FDFFD3; 303 | } 304 | 305 | pre.compile_fail { 306 | border-left: 2px solid rgba(255,0,0,.4); 307 | } 308 | 309 | pre.compile_fail:hover, .information:hover + pre.compile_fail { 310 | border-left: 2px solid #f00; 311 | } 312 | 313 | pre.ignore { 314 | border-left: 2px solid rgba(255,142,0,.4); 315 | } 316 | 317 | pre.ignore:hover, .information:hover + pre.ignore { 318 | border-left: 2px solid #ff9200; 319 | } 320 | 321 | .tooltip.compile_fail { 322 | color: rgba(255,0,0,.3); 323 | } 324 | 325 | .information > .compile_fail:hover { 326 | color: #f00; 327 | } 328 | 329 | .tooltip.ignore { 330 | color: rgba(255,142,0,.3); 331 | } 332 | 333 | .information > .ignore:hover { 334 | color: rgba(255,142,0,1); 335 | } 336 | 337 | .search-failed > a { 338 | color: #0089ff; 339 | } 340 | 341 | .tooltip .tooltiptext { 342 | background-color: black; 343 | color: #fff; 344 | } 345 | 346 | .tooltip .tooltiptext::after { 347 | border-color: transparent black transparent transparent; 348 | } 349 | 350 | .important-traits .tooltip .tooltiptext { 351 | background-color: white; 352 | color: black; 353 | border-color: black; 354 | } 355 | 356 | #titles > div { 357 | border-bottom-color: #ccc; 358 | } 359 | 360 | #titles > div.selected { 361 | border-bottom-color: #0078ee; 362 | } 363 | 364 | #titles > div:hover { 365 | border-bottom-color: #0089ff; 366 | } 367 | 368 | #titles > div > div.count { 369 | color: #888; 370 | } 371 | 372 | .modal { 373 | background-color: rgba(0,0,0,0.3); 374 | } 375 | 376 | .modal-content { 377 | background-color: #eee; 378 | border-color: #999; 379 | } 380 | 381 | .modal-content > .close { 382 | background-color: #eee; 383 | border-color: #999; 384 | } 385 | 386 | .modal-content > .close:hover { 387 | background-color: #ff1f1f; 388 | color: white; 389 | } 390 | 391 | .modal-content > .whiter { 392 | background-color: #eee; 393 | } 394 | 395 | .modal-content > .close:hover + .whiter { 396 | background-color: #ff1f1f; 397 | } 398 | 399 | @media (max-width: 700px) { 400 | .sidebar-menu { 401 | background-color: #F1F1F1; 402 | border-bottom-color: #e0e0e0; 403 | border-right-color: #e0e0e0; 404 | } 405 | 406 | .sidebar-elems { 407 | background-color: #F1F1F1; 408 | border-right-color: #000; 409 | } 410 | 411 | #sidebar-filler { 412 | background-color: #F1F1F1; 413 | border-bottom-color: #e0e0e0; 414 | } 415 | } 416 | 417 | kbd { 418 | color: #000; 419 | background-color: #fafbfc; 420 | border-color: #d1d5da; 421 | border-bottom-color: #c6cbd1; 422 | box-shadow-color: #c6cbd1; 423 | } 424 | 425 | #theme-picker, #settings-menu { 426 | border-color: #e0e0e0; 427 | background-color: #fff; 428 | } 429 | 430 | #theme-picker:hover, #theme-picker:focus, 431 | #settings-menu:hover, #settings-menu:focus { 432 | border-color: #717171; 433 | } 434 | 435 | #theme-choices { 436 | border-color: #ccc; 437 | background-color: #fff; 438 | } 439 | 440 | #theme-choices > button:not(:first-child) { 441 | border-top-color: #e0e0e0; 442 | } 443 | 444 | #theme-choices > button:hover, #theme-choices > button:focus { 445 | background-color: #eee; 446 | } 447 | 448 | @media (max-width: 700px) { 449 | #theme-picker { 450 | background: #fff; 451 | } 452 | } 453 | 454 | #all-types { 455 | background-color: #fff; 456 | } 457 | #all-types:hover { 458 | background-color: #f9f9f9; 459 | } 460 | -------------------------------------------------------------------------------- /doc/rustdoc.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2013 The Rust Project Developers. See the COPYRIGHT 3 | * file at the top-level directory of this distribution and at 4 | * http://rust-lang.org/COPYRIGHT. 5 | * 6 | * Licensed under the Apache License, Version 2.0 or the MIT license 8 | * , at your 9 | * option. This file may not be copied, modified, or distributed 10 | * except according to those terms. 11 | */ 12 | 13 | * { 14 | -webkit-box-sizing: border-box; 15 | -moz-box-sizing: border-box; 16 | box-sizing: border-box; 17 | } 18 | 19 | /* General structure and fonts */ 20 | 21 | body { 22 | font: 11pt sans-serif; 23 | line-height: 150%; 24 | margin: 0; 25 | position: relative; 26 | padding: 10px 15px 20px 15px; 27 | 28 | -webkit-font-feature-settings: "kern", "liga"; 29 | -moz-font-feature-settings: "kern", "liga"; 30 | font-feature-settings: "kern", "liga"; 31 | } 32 | 33 | body.source { 34 | padding: 10px 15px 20px 25px; 35 | } 36 | 37 | h1 { 38 | font-size: 1.5em; 39 | } 40 | h2 { 41 | font-size: 1.4em; 42 | } 43 | h3 { 44 | font-size: 1.3em; 45 | } 46 | h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.important), h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) { 47 | font-weight: 500; 48 | margin: 20px 0 15px 0; 49 | } 50 | h1.fqn { 51 | margin-top: 0; 52 | position: relative; 53 | } 54 | h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) { 55 | border-bottom: 1px solid; 56 | } 57 | h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant { 58 | font-weight: 600; 59 | margin-top: 10px; 60 | margin-bottom: 10px; 61 | position: relative; 62 | } 63 | h3.impl, h3.method, h3.type { 64 | padding-left: 15px; 65 | } 66 | 67 | ol, ul { 68 | padding-left: 25px; 69 | } 70 | ul ul, ol ul, ul ol, ol ol { 71 | margin-bottom: 0; 72 | } 73 | 74 | p { 75 | margin: 0 0 .6em 0; 76 | } 77 | 78 | summary { 79 | outline: none; 80 | } 81 | 82 | code, pre { 83 | white-space: pre-wrap; 84 | } 85 | .docblock code, .docblock-short code { 86 | border-radius: 3px; 87 | padding: 0 0.2em; 88 | } 89 | .docblock pre code, .docblock-short pre code, .docblock code.spotlight { 90 | padding: 0; 91 | } 92 | .docblock code.spotlight :last-child { 93 | padding-bottom: 0.6em; 94 | } 95 | pre { 96 | padding: 14px; 97 | margin-right: 20px; 98 | border-radius: 1.0em; 99 | background: #F3F3F3; 100 | box-shadow: inset 1pt 1pt 2pt #000000; 101 | } 102 | 103 | .source .content pre { 104 | padding: 20px; 105 | } 106 | 107 | img { 108 | max-width: 100%; 109 | } 110 | 111 | .source .content { 112 | max-width: none; 113 | overflow: visible; 114 | margin-left: 0px; 115 | min-width: 70em; 116 | } 117 | 118 | nav.sub { 119 | font-size: 16px; 120 | text-transform: uppercase; 121 | } 122 | 123 | .sidebar { 124 | width: 200px; 125 | position: fixed; 126 | left: 0; 127 | top: 0; 128 | height: 100vh; 129 | overflow: auto; 130 | } 131 | 132 | .sidebar .block > ul > li { 133 | margin-right: -10px; 134 | } 135 | 136 | /* Everything else */ 137 | 138 | .js-only, .hidden { 139 | display: none !important; 140 | } 141 | 142 | .sidebar img { 143 | margin: 20px auto; 144 | display: block; 145 | margin-top: 10px; 146 | } 147 | 148 | .sidebar .location { 149 | font-size: 17px; 150 | margin: 30px 10px 20px 10px; 151 | word-wrap: break-word; 152 | } 153 | 154 | .sidebar .version { 155 | font-size: 15px; 156 | text-align: center; 157 | border-bottom: 1px solid; 158 | overflow-wrap: break-word; 159 | word-wrap: break-word; /* deprecated */ 160 | word-break: break-word; /* Chrome, non-standard */ 161 | } 162 | 163 | .location:empty { 164 | border: none; 165 | } 166 | 167 | .location a:first-child { 168 | font-weight: 500; 169 | } 170 | 171 | .block { 172 | padding: 0; 173 | margin-bottom: 14px; 174 | } 175 | .block h2, .block h3 { 176 | margin-top: 0; 177 | margin-bottom: 8px; 178 | text-align: center; 179 | } 180 | .block ul, .block li { 181 | padding: 0; 182 | list-style: none; 183 | } 184 | 185 | .block a { 186 | padding-left: 10px; 187 | display: block; 188 | text-overflow: ellipsis; 189 | overflow: hidden; 190 | line-height: 24px; 191 | } 192 | 193 | .sidebar-title { 194 | border-top: 1px solid; 195 | border-bottom: 1px solid; 196 | text-align: center; 197 | font-size: 17px; 198 | margin-bottom: 5px; 199 | } 200 | 201 | .sidebar-links { 202 | margin-bottom: 15px; 203 | } 204 | 205 | .sidebar-links > a { 206 | padding-left: 10px; 207 | width: 100%; 208 | } 209 | 210 | .sidebar-menu { 211 | display: none; 212 | } 213 | 214 | .content { 215 | padding: 15px 0; 216 | border-radius: 13px; 217 | } 218 | 219 | .source .content pre.rust { 220 | white-space: pre; 221 | overflow: auto; 222 | } 223 | 224 | .source .sidebar { 225 | width: 0; 226 | } 227 | 228 | #search { 229 | position: relative; 230 | } 231 | 232 | #results { 233 | right: 0; 234 | left: 0; 235 | overflow: auto; 236 | } 237 | 238 | #results > table { 239 | width: 100%; 240 | table-layout: fixed; 241 | } 242 | 243 | div.files>a { 244 | display: block; 245 | padding: 0 3px; 246 | } 247 | 248 | #sidebar-toggle { 249 | position: fixed; 250 | top: 21px; 251 | left: 300px; 252 | z-index: 10; 253 | padding: 3px; 254 | border-top-right-radius: 3px; 255 | border-bottom-right-radius: 3px; 256 | cursor: pointer; 257 | font-weight: bold; 258 | transition: left .5s; 259 | font-size: 1.2em; 260 | border: 1px solid; 261 | border-left: 0; 262 | } 263 | #source-sidebar { 264 | position: fixed; 265 | top: 0; 266 | bottom: 0; 267 | left: 0; 268 | width: 300px; 269 | z-index: 1; 270 | overflow: auto; 271 | transition: left .5s; 272 | border-right: 1px solid; 273 | } 274 | #source-sidebar>.title { 275 | font-size: 1.5em; 276 | text-align: center; 277 | border-bottom: 1px solid; 278 | margin-bottom: 6px; 279 | } 280 | #source-sidebar { 281 | z-index: 11; 282 | } 283 | 284 | .content pre.line-numbers { 285 | float: left; 286 | border: none; 287 | position: relative; 288 | margin-left: 20px; 289 | 290 | -webkit-user-select: none; 291 | -moz-user-select: none; 292 | -ms-user-select: none; 293 | user-select: none; 294 | } 295 | .line-numbers span { 296 | cursor: pointer; 297 | } 298 | 299 | .docblock-short p { 300 | display: inline; 301 | } 302 | 303 | .docblock-short.nowrap { 304 | display: block; 305 | overflow: hidden; 306 | white-space: nowrap; 307 | text-overflow: ellipsis; 308 | } 309 | 310 | .docblock-short p { 311 | overflow: hidden; 312 | text-overflow: ellipsis; 313 | margin: 0; 314 | } 315 | .docblock-short code { 316 | white-space: nowrap; 317 | } 318 | 319 | .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { 320 | border-bottom: 1px solid; 321 | } 322 | 323 | #main > .docblock h1 { font-size: 1.3em; } 324 | #main > .docblock h2 { font-size: 1.15em; } 325 | #main > .docblock h3, #main > .docblock h4, #main > .docblock h5 { font-size: 1em; } 326 | 327 | .docblock h1 { font-size: 1.2em; } 328 | .docblock h2 { font-size: 0.95em; } 329 | .docblock h3, .docblock h4, .docblock h5 { font-size: 0.9em; } 330 | 331 | .docblock { 332 | margin-left: 24px; 333 | position: relative; 334 | } 335 | 336 | .content .out-of-band { 337 | font-size: 23px; 338 | margin: 0px; 339 | margin-right: 5px; 340 | padding: 0px; 341 | text-align: right; 342 | display: inline-block; 343 | font-weight: normal; 344 | position: absolute; 345 | right: 0; 346 | } 347 | 348 | .content > h3.impl, h3.impl { 349 | margin-top: 10pt; 350 | margin-bottom: 10pt; 351 | background-color: #D1D1D1; 352 | background-image: none; 353 | color: black; 354 | padding: 5pt; 355 | padding-left: 25px; 356 | box-shadow: 1px 1px 2px #000000; 357 | } 358 | 359 | .methods h3, h4 { 360 | margin-top: 10pt; 361 | margin-bottom: 10pt; 362 | box-shadow: 1px 1px 2px #000000; 363 | border-top-left-radius: 1em; 364 | border-bottom-left-radius: 1em; 365 | padding: 5pt 5pt 5pt 20pt; 366 | background: #D1D1D1; 367 | } 368 | 369 | h3.impl > .out-of-band { 370 | font-size: 21px; 371 | } 372 | 373 | h4.method > .out-of-band { 374 | font-size: 19px; 375 | } 376 | 377 | ul.item-list > li > .out-of-band { 378 | font-size: 19px; 379 | } 380 | 381 | h4 > code, h3 > code, .invisible > code { 382 | max-width: calc(100% - 41px); 383 | display: block; 384 | } 385 | 386 | .in-band, code { 387 | z-index: 5; 388 | } 389 | 390 | .invisible { 391 | width: 100%; 392 | } 393 | 394 | .content .in-band { 395 | margin: 0px; 396 | padding: 0px; 397 | } 398 | 399 | .in-band > code { 400 | display: inline-block; 401 | } 402 | 403 | #main { 404 | position: relative; 405 | } 406 | #main > .since { 407 | top: inherit; 408 | font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 409 | } 410 | 411 | .content table:not(.table-display) { 412 | border-spacing: 0 5px; 413 | border-collapse: separate; 414 | margin-left: 24px; 415 | } 416 | .content td { vertical-align: top; } 417 | .content td:first-child { padding-right: 20px; } 418 | .content td p:first-child { margin-top: 0; } 419 | .content td h1, .content td h2 { margin-left: 0; font-size: 1.1em; } 420 | 421 | .docblock table { 422 | margin: .5em 0; 423 | border-collapse: collapse; 424 | width: 100%; 425 | } 426 | 427 | .docblock table td { 428 | padding: .5em; 429 | } 430 | 431 | .docblock table th { 432 | padding: .5em; 433 | text-align: left; 434 | } 435 | 436 | .fields + table { 437 | margin-bottom: 1em; 438 | } 439 | 440 | .content .item-list { 441 | list-style-type: none; 442 | padding: 0; 443 | } 444 | 445 | .content .item-list li { 446 | margin-bottom: 1em; 447 | } 448 | 449 | .content .multi-column { 450 | -moz-column-count: 5; 451 | -moz-column-gap: 2.5em; 452 | -webkit-column-count: 5; 453 | -webkit-column-gap: 2.5em; 454 | column-count: 5; 455 | column-gap: 2.5em; 456 | } 457 | .content .multi-column li { width: 100%; display: inline-block; } 458 | 459 | .content .method { 460 | font-size: 1em; 461 | position: relative; 462 | margin-left: 20px; 463 | } 464 | /* Shift "where ..." part of method or fn definition down a line */ 465 | .content .method .where, 466 | .content .fn .where, 467 | .content .where.fmt-newline { 468 | display: block; 469 | font-size: 0.8em; 470 | } 471 | 472 | .content .methods > div:not(.important-traits) { 473 | margin-left: 40px; 474 | margin-bottom: 15px; 475 | } 476 | 477 | .content .impl-items .docblock, .content .impl-items .stability { 478 | margin-bottom: .6em; 479 | } 480 | .content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant { 481 | margin-left: 20px; 482 | } 483 | 484 | .content .stability code { 485 | font-size: 90%; 486 | } 487 | 488 | nav { 489 | padding-bottom: 10px; 490 | margin-bottom: 10px; 491 | } 492 | nav.main { 493 | padding: 20px 0; 494 | text-align: center; 495 | } 496 | nav.main .current { 497 | border-top: 1px solid; 498 | border-bottom: 1px solid; 499 | } 500 | nav.main .separator { 501 | border: 1px solid; 502 | display: inline-block; 503 | height: 23px; 504 | margin: 0 20px; 505 | } 506 | nav.sum { text-align: right; } 507 | nav.sub form { display: inline; } 508 | 509 | nav.sub, .content { 510 | margin-left: 210px; 511 | margin-right: 10pt; 512 | } 513 | 514 | .source nav.sub, .source .content { 515 | margin-left: 0px; 516 | } 517 | 518 | a { 519 | text-decoration: none; 520 | background: transparent; 521 | } 522 | 523 | .small-section-header:hover > .anchor { 524 | display: initial; 525 | } 526 | 527 | .in-band:hover > .anchor { 528 | display: inline-block; 529 | position: absolute; 530 | } 531 | .anchor { 532 | display: none; 533 | position: absolute; 534 | left: -7px; 535 | } 536 | .anchor.field { 537 | left: -5px; 538 | } 539 | .small-section-header > .anchor { 540 | left: -20px; 541 | } 542 | .small-section-header > .anchor:not(.field) { 543 | left: -28px; 544 | } 545 | .anchor:before { 546 | content: '\2002\00a7\2002'; 547 | } 548 | 549 | .docblock a:hover, .docblock-short a:hover, .stability a { 550 | text-decoration: underline; 551 | } 552 | 553 | .block a.current.crate { font-weight: 500; } 554 | 555 | .search-container { 556 | position: relative; 557 | } 558 | .search-container>div { 559 | display: inline-flex; 560 | width: calc(100% - 34px); 561 | } 562 | #crate-search { 563 | margin-top: 6px; 564 | padding: 6px; 565 | padding-right: 19px; 566 | flex: none; 567 | border: 0; 568 | border-right: 0; 569 | border-radius: 4px 0 0 4px; 570 | outline: none; 571 | cursor: pointer; 572 | border-right: 1px solid; 573 | -moz-appearance: none; 574 | -webkit-appearance: none; 575 | text-indent: 0.01px; 576 | text-overflow: ""; 577 | background-repeat: no-repeat; 578 | background-size: 20px; 579 | background-position: calc(100% - 1px) 56%; 580 | } 581 | .search-container>.top-button { 582 | position: absolute; 583 | right: 0; 584 | top: 10px; 585 | } 586 | .search-input { 587 | -moz-box-sizing: border-box !important; 588 | box-sizing: border-box !important; 589 | outline: none; 590 | border: 0; 591 | margin-top: 7px; 592 | margin-bottom: 1px; 593 | padding: 10px 16px; 594 | font-size: 17px; 595 | transition: border-color 300ms ease; 596 | transition: border-radius 300ms ease-in-out; 597 | transition: box-shadow 300ms ease-in-out; 598 | width: 100%; 599 | } 600 | #crate-search+.search-input { 601 | border-radius: 0 4px 4px 0; 602 | width: calc(100% - 32px); 603 | } 604 | .search-input:focus { 605 | border-radius: 2px; 606 | border: 0; 607 | outline: 0; 608 | } 609 | 610 | .search-results .desc { 611 | white-space: nowrap; 612 | text-overflow: ellipsis; 613 | overflow: hidden; 614 | display: block; 615 | } 616 | 617 | .search-results a { 618 | display: block; 619 | } 620 | 621 | .search-results a:hover[href] { 622 | border: 0; 623 | margin: 0; 624 | } 625 | 626 | .content .search-results td:first-child { 627 | padding-right: 0; 628 | width: 75%; 629 | } 630 | .content .search-results td:first-child a { 631 | padding-right: 10px; 632 | } 633 | .content .search-results td:first-child a span { 634 | float: left; 635 | } 636 | 637 | tr.result span.primitive::after { 638 | content: ' (primitive type)'; 639 | font-style: italic; 640 | } 641 | 642 | body.blur > :not(#help) { 643 | filter: blur(8px); 644 | -webkit-filter: blur(8px); 645 | opacity: .7; 646 | } 647 | 648 | #help { 649 | width: 100%; 650 | height: 100vh; 651 | position: fixed; 652 | top: 0; 653 | left: 0; 654 | display: flex; 655 | justify-content: center; 656 | align-items: center; 657 | } 658 | #help > div { 659 | flex: 0 0 auto; 660 | box-shadow: 0 0 6px rgba(0,0,0,.2); 661 | width: 550px; 662 | height: auto; 663 | border: 1px solid; 664 | } 665 | #help dt { 666 | float: left; 667 | clear: left; 668 | display: block; 669 | } 670 | #help dd { margin: 5px 35px; } 671 | #help .infos { padding-left: 0; } 672 | #help h1, #help h2 { margin-top: 0; } 673 | #help > div div { 674 | width: 50%; 675 | float: left; 676 | padding: 20px; 677 | padding-left: 17px; 678 | } 679 | 680 | .stab { 681 | display: table; 682 | border-width: 1px; 683 | border-style: solid; 684 | padding: 3px; 685 | margin-bottom: 5px; 686 | font-size: 90%; 687 | } 688 | .stab p { 689 | display: inline; 690 | } 691 | 692 | .stab summary { 693 | display: list-item; 694 | } 695 | 696 | .stab .microscope { 697 | font-size: 1.5em; 698 | } 699 | 700 | .module-item .stab { 701 | display: inline; 702 | border-width: 0; 703 | padding: 0; 704 | margin: 0; 705 | background: inherit !important; 706 | } 707 | 708 | .module-item.unstable { 709 | opacity: 0.65; 710 | } 711 | 712 | .since { 713 | font-weight: normal; 714 | font-size: initial; 715 | position: absolute; 716 | right: 0; 717 | top: 0; 718 | } 719 | 720 | .variants_table { 721 | width: 100%; 722 | } 723 | 724 | .variants_table tbody tr td:first-child { 725 | width: 1%; /* make the variant name as small as possible */ 726 | } 727 | 728 | td.summary-column { 729 | width: 100%; 730 | } 731 | 732 | .summary { 733 | padding-right: 0px; 734 | } 735 | 736 | pre.rust .question-mark { 737 | font-weight: bold; 738 | } 739 | 740 | a.test-arrow { 741 | display: inline-block; 742 | position: absolute; 743 | padding: 5px 10px 5px 10px; 744 | border-radius: 5px; 745 | font-size: 130%; 746 | top: 5px; 747 | right: 5px; 748 | } 749 | a.test-arrow:hover{ 750 | text-decoration: none; 751 | } 752 | 753 | .section-header:hover a:before { 754 | position: absolute; 755 | left: -25px; 756 | content: '\2002\00a7\2002'; 757 | } 758 | 759 | .section-header:hover a { 760 | text-decoration: none; 761 | } 762 | 763 | .section-header a { 764 | color: inherit; 765 | } 766 | 767 | .collapse-toggle { 768 | font-weight: 300; 769 | position: absolute; 770 | left: 1px; 771 | top: 1px; 772 | } 773 | 774 | h3 > .collapse-toggle { 775 | font-size: 0.8em; 776 | top: 5pt; 777 | } 778 | 779 | h4 > .collapse-toggle { 780 | font-size: 0.8em; 781 | top: 7px; 782 | } 783 | 784 | .toggle-wrapper > .collapse-toggle { 785 | left: -24px; 786 | margin-top: 0px; 787 | } 788 | 789 | .toggle-wrapper { 790 | position: relative; 791 | margin-top: 5px; 792 | } 793 | 794 | .toggle-wrapper.collapsed { 795 | height: 25px; 796 | transition: height .2s; 797 | margin-bottom: .6em; 798 | } 799 | 800 | .collapse-toggle > .inner { 801 | display: inline-block; 802 | width: 1.2ch; 803 | text-align: center; 804 | } 805 | 806 | .ghost { 807 | display: none; 808 | } 809 | 810 | .ghost + .since { 811 | position: initial; 812 | display: table-cell; 813 | } 814 | 815 | .since + .srclink { 816 | display: table-cell; 817 | padding-left: 10px; 818 | } 819 | 820 | .item-spacer { 821 | width: 100%; 822 | height: 12px; 823 | } 824 | 825 | span.since { 826 | position: initial; 827 | font-size: 20px; 828 | margin-right: 5px; 829 | } 830 | 831 | .toggle-wrapper > .collapse-toggle { 832 | left: 0; 833 | } 834 | 835 | .variant + .toggle-wrapper + .docblock > p { 836 | margin-top: 5px; 837 | } 838 | 839 | .sub-variant, .sub-variant > h3 { 840 | margin-top: 0 !important; 841 | } 842 | 843 | .toggle-label { 844 | display: inline-block; 845 | margin-left: 4px; 846 | margin-top: 3px; 847 | } 848 | 849 | .enum > .toggle-wrapper + .docblock, .struct > .toggle-wrapper + .docblock { 850 | margin-left: 30px; 851 | margin-bottom: 20px; 852 | margin-top: 5px; 853 | } 854 | 855 | .docblock > .section-header:first-child { 856 | margin-left: 15px; 857 | margin-top: 0; 858 | } 859 | 860 | .docblock > .section-header:first-child:hover > a:before { 861 | left: -10px; 862 | } 863 | 864 | .enum > .collapsed, .struct > .collapsed { 865 | margin-bottom: 25px; 866 | } 867 | 868 | #main > .variant, #main > .structfield { 869 | margin-left: 24px; 870 | display: block; 871 | } 872 | 873 | .attributes { 874 | display: block; 875 | margin: 0px 0px 0px 30px !important; 876 | } 877 | .toggle-attributes.collapsed { 878 | margin-bottom: 5px; 879 | } 880 | 881 | :target > code { 882 | opacity: 1; 883 | } 884 | 885 | /* Media Queries */ 886 | 887 | @media (max-width: 700px) { 888 | body { 889 | padding-top: 0px; 890 | } 891 | 892 | .sidebar { 893 | height: 45px; 894 | min-height: 40px; 895 | width: calc(100% + 30px); 896 | margin: 0; 897 | margin-left: -15px; 898 | padding: 0 15px; 899 | position: static; 900 | z-index: 1; 901 | } 902 | 903 | .sidebar > .location { 904 | float: right; 905 | margin: 0px; 906 | margin-top: 2px; 907 | padding: 3px 10px 1px 10px; 908 | min-height: 39px; 909 | background: inherit; 910 | text-align: left; 911 | font-size: 24px; 912 | } 913 | 914 | .sidebar .location:empty { 915 | padding: 0; 916 | } 917 | 918 | .sidebar img { 919 | width: 35px; 920 | margin-top: 5px; 921 | margin-bottom: 5px; 922 | float: left; 923 | margin-left: 50px; 924 | } 925 | 926 | .sidebar-menu { 927 | position: fixed; 928 | z-index: 10; 929 | font-size: 2rem; 930 | cursor: pointer; 931 | width: 45px; 932 | left: 0; 933 | text-align: center; 934 | display: block; 935 | border-bottom: 1px solid; 936 | border-right: 1px solid; 937 | height: 45px; 938 | } 939 | 940 | .sidebar-elems { 941 | position: fixed; 942 | z-index: 1; 943 | left: 0; 944 | top: 45px; 945 | bottom: 0; 946 | overflow-y: auto; 947 | border-right: 1px solid; 948 | display: none; 949 | } 950 | 951 | .sidebar > .block.version { 952 | border-bottom: none; 953 | margin-top: 12px; 954 | } 955 | 956 | nav.sub { 957 | width: calc(100% - 32px); 958 | float: right; 959 | } 960 | 961 | .content { 962 | margin-left: 0px; 963 | } 964 | 965 | #main { 966 | margin-top: 45px; 967 | padding: 0; 968 | } 969 | 970 | .content .in-band { 971 | width: 100%; 972 | } 973 | 974 | .content h4 > .out-of-band { 975 | position: inherit; 976 | } 977 | 978 | .toggle-wrapper > .collapse-toggle { 979 | left: 0px; 980 | } 981 | 982 | .toggle-wrapper { 983 | height: 1.5em; 984 | } 985 | 986 | #search { 987 | margin-left: 0; 988 | } 989 | 990 | .content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant { 991 | display: flex; 992 | } 993 | 994 | .anchor { 995 | display: none !important; 996 | } 997 | } 998 | 999 | @media print { 1000 | nav.sub, .content .out-of-band, .collapse-toggle { 1001 | display: none; 1002 | } 1003 | } 1004 | 1005 | .information { 1006 | position: absolute; 1007 | left: -20px; 1008 | margin-top: 7px; 1009 | z-index: 1; 1010 | } 1011 | 1012 | .tooltip { 1013 | position: relative; 1014 | display: inline-block; 1015 | cursor: pointer; 1016 | } 1017 | 1018 | .tooltip .tooltiptext { 1019 | width: 120px; 1020 | display: none; 1021 | text-align: center; 1022 | padding: 5px 3px; 1023 | border-radius: 6px; 1024 | margin-left: 5px; 1025 | top: -5px; 1026 | left: 105%; 1027 | z-index: 1; 1028 | } 1029 | 1030 | .tooltip:hover .tooltiptext { 1031 | display: inline; 1032 | } 1033 | 1034 | .tooltip .tooltiptext::after { 1035 | content: " "; 1036 | position: absolute; 1037 | top: 50%; 1038 | left: 11px; 1039 | margin-top: -5px; 1040 | border-width: 5px; 1041 | border-style: solid; 1042 | } 1043 | 1044 | .important-traits .tooltip .tooltiptext { 1045 | border: 1px solid; 1046 | } 1047 | 1048 | pre.rust { 1049 | position: relative; 1050 | } 1051 | 1052 | .search-failed { 1053 | text-align: center; 1054 | margin-top: 20px; 1055 | } 1056 | 1057 | #titles { 1058 | height: 35px; 1059 | } 1060 | 1061 | #titles > div { 1062 | float: left; 1063 | width: 33.3%; 1064 | text-align: center; 1065 | border-bottom: 1px solid; 1066 | font-size: 18px; 1067 | cursor: pointer; 1068 | } 1069 | 1070 | #titles > div.selected { 1071 | border-bottom: 3px solid; 1072 | } 1073 | 1074 | #titles > div:hover { 1075 | border-bottom: 3px solid; 1076 | } 1077 | 1078 | #titles > div > div.count { 1079 | display: inline-block; 1080 | font-size: 16px; 1081 | } 1082 | 1083 | .important-traits { 1084 | cursor: pointer; 1085 | z-index: 2; 1086 | } 1087 | 1088 | h4 > .important-traits { 1089 | position: absolute; 1090 | left: -44px; 1091 | top: 2px; 1092 | } 1093 | 1094 | @media (max-width: 700px) { 1095 | h4 > .important-traits { 1096 | position: absolute; 1097 | left: -22px; 1098 | top: 24px; 1099 | } 1100 | 1101 | #titles > div > div.count { 1102 | float: left; 1103 | width: 100%; 1104 | } 1105 | 1106 | #titles { 1107 | height: 50px; 1108 | } 1109 | 1110 | .sidebar.mobile { 1111 | position: fixed; 1112 | width: 100%; 1113 | margin-left: 0; 1114 | background-color: rgba(0,0,0,0); 1115 | height: 100%; 1116 | } 1117 | 1118 | .show-it { 1119 | display: block; 1120 | width: 246px; 1121 | } 1122 | 1123 | .show-it > .block.items { 1124 | margin: 8px 0; 1125 | } 1126 | 1127 | .show-it > .block.items > ul { 1128 | margin: 0; 1129 | } 1130 | 1131 | .show-it > .block.items > ul > li { 1132 | text-align: center; 1133 | margin: 2px 0; 1134 | } 1135 | 1136 | .show-it > .block.items > ul > li > a { 1137 | font-size: 21px; 1138 | } 1139 | 1140 | /* Because of ios, we need to actually have a full height sidebar title so the 1141 | * actual sidebar can show up. But then we need to make it transparent so we don't 1142 | * hide content. The filler just allows to create the background for the sidebar 1143 | * title. But because of the absolute position, I had to lower the z-index. 1144 | */ 1145 | #sidebar-filler { 1146 | position: fixed; 1147 | left: 45px; 1148 | width: calc(100% - 45px); 1149 | top: 0; 1150 | height: 45px; 1151 | z-index: -1; 1152 | border-bottom: 1px solid; 1153 | } 1154 | 1155 | .collapse-toggle { 1156 | left: -20px; 1157 | } 1158 | 1159 | .impl > .collapse-toggle { 1160 | left: -10px; 1161 | } 1162 | } 1163 | 1164 | 1165 | @media (max-width: 416px) { 1166 | #titles { 1167 | height: 73px; 1168 | } 1169 | 1170 | #titles > div { 1171 | height: 73px; 1172 | } 1173 | } 1174 | 1175 | .modal { 1176 | position: fixed; 1177 | width: 100vw; 1178 | height: 100vh; 1179 | z-index: 10000; 1180 | top: 0; 1181 | left: 0; 1182 | } 1183 | 1184 | .modal-content { 1185 | display: block; 1186 | max-width: 60%; 1187 | min-width: 200px; 1188 | padding: 8px; 1189 | top: 40%; 1190 | position: absolute; 1191 | left: 50%; 1192 | transform: translate(-50%, -40%); 1193 | border: 1px solid; 1194 | border-radius: 4px; 1195 | border-top-right-radius: 0; 1196 | } 1197 | 1198 | .modal-content > .docblock { 1199 | margin: 0; 1200 | } 1201 | 1202 | h3.important { 1203 | margin: 0; 1204 | margin-bottom: 13px; 1205 | font-size: 19px; 1206 | } 1207 | 1208 | .modal-content > .docblock > code.content { 1209 | margin: 0; 1210 | padding: 0; 1211 | font-size: 20px; 1212 | } 1213 | 1214 | .modal-content > .close { 1215 | position: absolute; 1216 | font-weight: 900; 1217 | right: -25px; 1218 | top: -1px; 1219 | font-size: 18px; 1220 | width: 25px; 1221 | padding-right: 2px; 1222 | border-top-right-radius: 5px; 1223 | border-bottom-right-radius: 5px; 1224 | text-align: center; 1225 | border: 1px solid; 1226 | border-right: 0; 1227 | cursor: pointer; 1228 | } 1229 | 1230 | .modal-content > .whiter { 1231 | height: 25px; 1232 | position: absolute; 1233 | width: 3px; 1234 | right: -2px; 1235 | top: 0px; 1236 | } 1237 | 1238 | #main > div.important-traits { 1239 | position: absolute; 1240 | left: -24px; 1241 | margin-top: 16px; 1242 | } 1243 | 1244 | .content > .methods > div.important-traits { 1245 | position: absolute; 1246 | left: -42px; 1247 | margin-top: 2px; 1248 | } 1249 | 1250 | kbd { 1251 | display: inline-block; 1252 | padding: 3px 5px; 1253 | font: 15px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 1254 | line-height: 10px; 1255 | vertical-align: middle; 1256 | border: solid 1px; 1257 | border-radius: 3px; 1258 | box-shadow: inset 0 -1px 0; 1259 | cursor: default; 1260 | } 1261 | 1262 | .theme-picker { 1263 | display: none; 1264 | } 1265 | 1266 | .theme-picker button { 1267 | outline: none; 1268 | } 1269 | 1270 | #settings-menu { 1271 | position: absolute; 1272 | right: 0; 1273 | top: 13px; 1274 | outline: none; 1275 | } 1276 | 1277 | #theme-picker, #settings-menu { 1278 | padding: 4px; 1279 | width: 27px; 1280 | height: 29px; 1281 | border: 1px solid; 1282 | border-radius: 3px; 1283 | cursor: pointer; 1284 | } 1285 | 1286 | #theme-choices { 1287 | display: none; 1288 | position: absolute; 1289 | left: 0; 1290 | top: 28px; 1291 | border: 1px solid; 1292 | border-radius: 3px; 1293 | z-index: 1; 1294 | cursor: pointer; 1295 | } 1296 | 1297 | #theme-choices > button { 1298 | border: none; 1299 | width: 100%; 1300 | padding: 4px; 1301 | text-align: center; 1302 | background: rgba(0,0,0,0); 1303 | } 1304 | 1305 | #theme-choices > button:not(:first-child) { 1306 | border-top: 1px solid; 1307 | } 1308 | 1309 | @media (max-width: 700px) { 1310 | .theme-picker { 1311 | left: 10px; 1312 | top: 54px; 1313 | z-index: 1; 1314 | } 1315 | } 1316 | 1317 | .hidden-by-impl-hider, 1318 | .hidden-by-usual-hider { 1319 | /* important because of conflicting rule for small screens */ 1320 | display: none !important; 1321 | } 1322 | 1323 | #implementations-list > h3 > span.in-band { 1324 | width: 100%; 1325 | } 1326 | 1327 | .table-display { 1328 | width: 100%; 1329 | border: 0; 1330 | border-collapse: collapse; 1331 | border-spacing: 0; 1332 | font-size: 16px; 1333 | } 1334 | 1335 | .table-display tr td:first-child { 1336 | padding-right: 0; 1337 | } 1338 | 1339 | .table-display tr td:last-child { 1340 | float: right; 1341 | } 1342 | .table-display .out-of-band { 1343 | position: relative; 1344 | font-size: 19px; 1345 | display: block; 1346 | } 1347 | 1348 | #main > ul { 1349 | padding-left: 10px; 1350 | } 1351 | #main > ul > li { 1352 | list-style: none; 1353 | } 1354 | #all-types { 1355 | text-align: center; 1356 | border: 1px solid; 1357 | margin: 0 10px; 1358 | margin-bottom: 10px; 1359 | display: block; 1360 | border-radius: 7px; 1361 | } 1362 | #all-types > p { 1363 | margin: 5px 0; 1364 | } 1365 | 1366 | div.children { 1367 | padding-left: 27px; 1368 | display: none; 1369 | } 1370 | div.name { 1371 | cursor: pointer; 1372 | position: relative; 1373 | margin-left: 16px; 1374 | } 1375 | div.name:hover { 1376 | border: 1px dotted #000000; 1377 | margin: -1px -1px -1px 15px; 1378 | } 1379 | div.files>a { 1380 | display: block; 1381 | padding: 0 3px; 1382 | } 1383 | div.files>a:hover { 1384 | border: 1px dotted #000000; 1385 | margin: -1px -1px -1px -1px; 1386 | } 1387 | div.name.expand+.children { 1388 | display: block; 1389 | } 1390 | div.name::before { 1391 | content: "\25B6"; 1392 | padding-left: 4px; 1393 | font-size: 0.7em; 1394 | position: absolute; 1395 | left: -16px; 1396 | top: 4px; 1397 | } 1398 | div.name.expand::before { 1399 | transform: rotate(90deg); 1400 | left: -15px; 1401 | top: 2px; 1402 | } 1403 | -------------------------------------------------------------------------------- /gnuplot/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "gnuplot" 4 | version = "0.0.46" #auto 5 | license = "LGPL-3.0" 6 | repository = "https://github.com/SiegeLord/RustGnuplot" 7 | documentation = "http://siegelord.github.io/RustGnuplot/doc/gnuplot/index.html" 8 | keywords = ["plots", "graphics", "plotting", "gnuplot", "visualization"] 9 | authors = [ "SiegeLord " ] 10 | description = "Rust gnuplot controller" 11 | autobins = false 12 | autoexamples = false 13 | autotests = false 14 | autobenches = false 15 | categories = ["visualization"] 16 | edition = "2021" 17 | 18 | [lib] 19 | 20 | name = "gnuplot" 21 | path = "src/lib.rs" 22 | 23 | [dev-dependencies] 24 | 25 | argparse-rs = "=0.1.0" 26 | tempfile = "3.3.0" 27 | 28 | [[example]] 29 | 30 | name = "example1" 31 | path = "examples/example1.rs" 32 | 33 | [[example]] 34 | 35 | name = "example2" 36 | path = "examples/example2.rs" 37 | 38 | [[example]] 39 | 40 | name = "example3" 41 | path = "examples/example3.rs" 42 | 43 | [[example]] 44 | 45 | name = "example4" 46 | path = "examples/example4.rs" 47 | 48 | [[example]] 49 | 50 | name = "animation_example" 51 | path = "examples/animation_example.rs" 52 | 53 | [[example]] 54 | 55 | name = "box_and_whisker" 56 | path = "examples/box_and_whisker.rs" 57 | 58 | [[example]] 59 | 60 | name = "box_xy_error" 61 | path = "examples/box_xy_error.rs" 62 | 63 | [[example]] 64 | 65 | name = "color" 66 | path = "examples/color.rs" 67 | 68 | [[example]] 69 | 70 | name = "variable_color" 71 | path = "examples/variable_color.rs" 72 | 73 | [[example]] 74 | 75 | name = "lines_3d" 76 | path = "examples/lines_3d.rs" 77 | 78 | [[example]] 79 | 80 | name = "points_3d" 81 | path = "examples/points_3d.rs" 82 | 83 | [[example]] 84 | 85 | name = "lines_points_3d" 86 | path = "examples/lines_points_3d.rs" 87 | 88 | [[example]] 89 | 90 | name = "readme_example" 91 | path = "examples/readme_example.rs" 92 | 93 | [[example]] 94 | 95 | name = "time" 96 | path = "examples/time.rs" 97 | 98 | [[example]] 99 | 100 | name = "gif" 101 | path = "examples/gif.rs" 102 | 103 | [[example]] 104 | 105 | name = "color_cycling" 106 | path = "examples/color_cycling.rs" 107 | 108 | [[example]] 109 | 110 | name = "dash_type" 111 | path = "examples/dash_type.rs" 112 | 113 | [[example]] 114 | 115 | name = "patterns" 116 | path = "examples/patterns.rs" 117 | 118 | [[example]] 119 | 120 | name = "inverse_api" 121 | path = "examples/inverse_api.rs" 122 | 123 | [[example]] 124 | 125 | name = "multiplot_options" 126 | path = "examples/multiplot_options.rs" 127 | 128 | [[example]] 129 | 130 | name = "multiple_axes" 131 | path = "examples/multiple_axes.rs" 132 | 133 | [[example]] 134 | 135 | name = "text" 136 | path = "examples/text.rs" 137 | 138 | [[example]] 139 | 140 | name = "polygons" 141 | path = "examples/polygons.rs" 142 | 143 | [dependencies] 144 | byteorder = "1.4.3" 145 | tempfile = "3.9" 146 | -------------------------------------------------------------------------------- /gnuplot/examples/animation_example.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use gnuplot::*; 3 | use std::thread::sleep; 4 | use std::time::Duration; 5 | 6 | fn main() 7 | { 8 | println!("This is a silly example of doing an animation... Ctrl-C to quit."); 9 | let mut fg = Figure::new(); 10 | let mut x = vec![]; 11 | for i in 0..100i32 12 | { 13 | x.push(i as f32 * 0.1 - 5.0); 14 | } 15 | 16 | let mut t = 0.0; 17 | loop 18 | { 19 | fg.clear_axes(); 20 | fg.axes2d().set_y_range(Fix(-1.0), Fix(1.0)).lines( 21 | x.iter(), 22 | x.iter().map(|&x| (x + t).sin()), 23 | &[], 24 | ); 25 | t += 0.1; 26 | fg.show_and_keep_running().unwrap(); 27 | sleep(Duration::from_millis(500)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /gnuplot/examples/box_and_whisker.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | 5 | mod common; 6 | 7 | fn example(c: Common) 8 | { 9 | let mut fg = Figure::new(); 10 | 11 | fg.axes2d() 12 | .set_title("Box and whisker", &[]) 13 | .box_and_whisker( 14 | [-0.6f32, 1.5, 2.5].iter(), 15 | [-1.0f32, 0.0, 1.0].iter(), 16 | [-2.0f32, -1.0, 0.0].iter(), 17 | [2.0f32, 3.0, 4.0].iter(), 18 | [1.0f32, 2.0, 3.0].iter(), 19 | &[ 20 | BoxWidth([0.5f64, 0.25, 0.125].into()), 21 | WhiskerBars(0.5), 22 | Color("blue".into()), 23 | LineWidth(2.0), 24 | LineStyle(SmallDot), 25 | FillAlpha(0.5), 26 | ], 27 | ) 28 | .box_and_whisker( 29 | [0.0f32, 1.0, 2.0].iter(), 30 | [-1.0f32, 0.0, 1.0].iter(), 31 | [-2.0f32, -1.0, 0.0].iter(), 32 | [2.0f32, 3.0, 4.0].iter(), 33 | [1.0f32, 2.0, 3.0].iter(), 34 | &[], 35 | ) 36 | .set_x_range(Fix(-1.0), Fix(3.0)) 37 | .set_y_range(Fix(-3.0), Fix(5.0)); 38 | 39 | c.show(&mut fg, "box_and_whisker"); 40 | } 41 | 42 | fn main() 43 | { 44 | Common::new().map(|c| example(c)); 45 | } 46 | -------------------------------------------------------------------------------- /gnuplot/examples/box_xy_error.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | 5 | mod common; 6 | 7 | fn example(c: Common) 8 | { 9 | let mut fg = Figure::new(); 10 | 11 | fg.axes2d() 12 | .set_title("Box XY Error", &[]) 13 | .box_xy_error_delta( 14 | [0.0f32, 1.0, 2.0].iter(), 15 | [-1.0f32, 0.0, 1.0].iter(), 16 | [0.25f32, 0.375, 0.15].iter(), 17 | [2.0f32, 3.0, 4.0].iter(), 18 | &[], 19 | ) 20 | .box_xy_error_low_high( 21 | [-0.6f32, 1.5, 2.5].iter(), 22 | [-1.0f32, 0.0, 1.0].iter(), 23 | [-0.9f32, -1.0, 2.2].iter(), 24 | [-0.45f32, 3.0, 2.95].iter(), 25 | [-1.5f32, 4.5, 3.0].iter(), 26 | [0.5f32, 4.75, 0.125].iter(), 27 | &[ 28 | Color("blue".into()), 29 | LineWidth(2.0), 30 | LineStyle(SmallDot), 31 | FillAlpha(0.5), 32 | ], 33 | ) 34 | .set_x_range(Fix(-1.0), Fix(3.0)) 35 | .set_y_range(Fix(-3.0), Fix(5.0)); 36 | 37 | c.show(&mut fg, "box_xy_error"); 38 | } 39 | 40 | fn main() 41 | { 42 | Common::new().map(|c| example(c)); 43 | } 44 | -------------------------------------------------------------------------------- /gnuplot/examples/color.rs: -------------------------------------------------------------------------------- 1 | use std::{fmt::Debug, iter}; 2 | 3 | // This file is released into Public Domain. 4 | use crate::common::*; 5 | use gnuplot::*; 6 | 7 | mod common; 8 | 9 | fn color_name(color: &PlotOption) -> String 10 | { 11 | match color 12 | { 13 | Color(color_type) => format!("{:?}", color_type), 14 | _ => panic!(), 15 | } 16 | } 17 | 18 | fn example(c: Common) 19 | { 20 | let x = 0..5; 21 | 22 | let colors = [ 23 | Color("black".into()), // Conversion to RGBString is implicit 24 | Color(ColorType::RGBString("black")), // Explicit use of RGBString 25 | Color("red".into()), // Conversion to RGBString is implicit 26 | Color(RGBString("#ff0000")), // Red using Hex coded RRGGBB 27 | Color(RGBString("#ffff0000")), // Red using Hex coded AARRGGBB 28 | Color("#ff8888".into()), // Pink using Hex coded RRGGBB. Conversion to RGBString is implict 29 | Color("#77ff0000".into()), // Pink using Hex coded AARRGGBB. Conversion to RGBString is implict 30 | Color(ColorType::RGBString("#ffff0000")), // Transparent using Hex coded AARRGGBB 31 | Color((128, 0, 255).into()), // Purple using implict RGBInteger 32 | Color(RGBInteger(128, 0, 255)), // Purple using explict RGBInteger 33 | Color((0.5, 0.0, 1.0).try_into().unwrap()), // Purple using implict float to int conversion 34 | Color((64, 128, 0, 255).into()), // Pale purple using implict ARGBInteger 35 | Color(ARGBInteger(64, 128, 0, 255)), // Pale purple using explict ARGBInteger 36 | Color((0.25, 0.5, 0.0, 1.0).try_into().unwrap()), // Pale purple using implict float to int conversion 37 | ]; 38 | 39 | let mut fg = Figure::new(); 40 | let ax = fg.axes2d(); 41 | ax.set_title( 42 | "Demo of RGBString in various forms\nSee code comments for how to construct the colors", 43 | &[], 44 | ) 45 | .set_x_range(Fix(-9.0), Auto) 46 | .set_legend(Graph(0.5), Graph(0.9), &[], &[Font("", 12.0)]); 47 | 48 | let n_colors = colors.len(); 49 | for (i, color) in colors.into_iter().enumerate() 50 | { 51 | ax.box_xy_error_delta( 52 | x.clone(), 53 | iter::repeat((n_colors - 1) - i), 54 | iter::repeat(0.4), 55 | iter::repeat(0.2), 56 | &[ 57 | Caption(&color_name(&color)), 58 | LineWidth(1.0), 59 | BorderColor("black".into()), 60 | color, 61 | ], 62 | ); 63 | } 64 | 65 | // Draw line across the boxes in fixed black and background colors 66 | ax.lines( 67 | [0, 0], 68 | [0, n_colors - 1], 69 | &[ 70 | LineWidth(7.0), 71 | Color(Black), 72 | Caption(&color_name::(&Color(Black))), 73 | ], 74 | ); 75 | 76 | ax.lines( 77 | [4, 4], 78 | [0, n_colors - 1], 79 | &[ 80 | LineWidth(7.0), 81 | Color(Background), 82 | Caption(&color_name::(&Color(Background))), 83 | ], 84 | ); 85 | 86 | // any of the forms used for Color can also be used with TextColor and BorderColor 87 | ax.set_x_label( 88 | "Labels can be colored using TextColor", 89 | &[TextColor((128, 0, 255).into())], 90 | ); 91 | 92 | c.show(&mut fg, "rgb_color"); 93 | 94 | // ######################################################################## 95 | 96 | let mut fg = Figure::new(); 97 | let ax = fg.axes2d(); 98 | let max_cb = 10.0; 99 | ax.set_cb_range(Fix(0.0), Fix(max_cb)); 100 | for color_value in (0..=10).into_iter().step_by(2) 101 | { 102 | let color_float = color_value as f64; 103 | let frac_color = Color(PaletteFracColor(color_float / max_cb)); 104 | let cb_range_color = Color(PaletteCBColor(color_float)); 105 | 106 | ax.box_xy_error_delta( 107 | [color_value], 108 | [0], 109 | [0.4], 110 | [0.4], 111 | &[ 112 | Caption(&color_name(&frac_color)), 113 | LineWidth(1.0), 114 | BorderColor("black".into()), 115 | frac_color, 116 | ], 117 | ) 118 | .box_xy_error_delta( 119 | [color_value], 120 | [1], 121 | [0.4], 122 | [0.4], 123 | &[ 124 | Caption(&color_name(&cb_range_color)), 125 | LineWidth(1.0), 126 | BorderColor("black".into()), 127 | cb_range_color, 128 | ], 129 | ); 130 | } 131 | ax.set_x_range(Fix(-10.0), Fix(11.0)) 132 | .set_y_range(Fix(-0.5), Fix(1.5)) 133 | .set_legend(Graph(0.45), Graph(0.9), &[], &[Font("", 12.0)]); 134 | c.show(&mut fg, "palette_colors"); 135 | } 136 | 137 | fn main() 138 | { 139 | Common::new().map(|c| example(c)); 140 | } 141 | -------------------------------------------------------------------------------- /gnuplot/examples/color_cycling.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | 5 | mod common; 6 | 7 | fn example(c: Common) 8 | { 9 | let x = 0..10; 10 | 11 | let mut fg = Figure::new(); 12 | 13 | let ax = fg.axes2d(); 14 | ax.set_title("Color cycling", &[]); 15 | ax.set_legend(Graph(0.2), Graph(0.9), &[], &[]); 16 | for i in 0..10 17 | { 18 | ax.lines_points( 19 | x.clone(), 20 | x.clone().map(|v| v * 2 + i), 21 | &[Caption(&format!("{}", i))], 22 | ); 23 | } 24 | 25 | c.show(&mut fg, "color_cycling"); 26 | } 27 | 28 | fn main() 29 | { 30 | Common::new().map(|c| example(c)); 31 | } 32 | -------------------------------------------------------------------------------- /gnuplot/examples/common.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | #![allow(dead_code)] 3 | use argparse_rs::*; 4 | use gnuplot::*; 5 | use std::env; 6 | use std::path::Path; 7 | 8 | #[derive(Copy, Clone)] 9 | pub struct BetterIterator<'l, T: 'l> 10 | { 11 | idx: usize, 12 | slice: &'l [T], 13 | } 14 | 15 | impl<'l, T: 'l> Iterator for BetterIterator<'l, T> 16 | { 17 | type Item = &'l T; 18 | fn next(&mut self) -> Option<&'l T> 19 | { 20 | let ret = self.slice.get(self.idx); 21 | self.idx += 1; 22 | ret 23 | } 24 | } 25 | 26 | pub trait BetterIteratorExt<'l, T> 27 | { 28 | fn iter2(self) -> BetterIterator<'l, T>; 29 | } 30 | 31 | impl<'l, T: 'l> BetterIteratorExt<'l, T> for &'l [T] 32 | { 33 | fn iter2(self) -> BetterIterator<'l, T> 34 | { 35 | BetterIterator { 36 | idx: 0, 37 | slice: self, 38 | } 39 | } 40 | } 41 | 42 | pub struct Common 43 | { 44 | pub no_show: bool, 45 | pub save_png: bool, 46 | pub term: Option, 47 | pub extension: String, 48 | pub output_dir: String, 49 | pub echo: bool, 50 | } 51 | 52 | impl Common 53 | { 54 | pub fn new() -> Option 55 | { 56 | let arg_vec: Vec<_> = env::args().collect(); 57 | 58 | let mut args = ArgParser::new(arg_vec[0].clone()); 59 | 60 | args.add_opt( 61 | "no-show", 62 | Some("false"), 63 | 'n', 64 | false, 65 | "do not run the gnuplot process.", 66 | ArgType::Flag, 67 | ); 68 | args.add_opt( 69 | "terminal", 70 | None, 71 | 't', 72 | false, 73 | "specify what terminal to use for gnuplot.", 74 | ArgType::Option, 75 | ); 76 | args.add_opt( 77 | "output-dir", 78 | None, 79 | 'o', 80 | false, 81 | "output directory.", 82 | ArgType::Option, 83 | ); 84 | args.add_opt( 85 | "extension", 86 | Some("out"), 87 | 'e', 88 | false, 89 | "specify what extension the output file should have. Default: 'out'", 90 | ArgType::Option, 91 | ); 92 | args.add_opt( 93 | "save-png", 94 | Some("false"), 95 | 's', 96 | false, 97 | "render the plots to images.", 98 | ArgType::Flag, 99 | ); 100 | args.add_opt( 101 | "echo", 102 | Some("false"), 103 | 'g', 104 | false, 105 | "echo gnuplot commands.", 106 | ArgType::Flag, 107 | ); 108 | 109 | let res = args.parse(arg_vec.iter()).unwrap(); 110 | 111 | if res.get("help").unwrap_or(false) 112 | { 113 | args.help(); 114 | return None; 115 | } 116 | 117 | Some(Common { 118 | output_dir: res.get("output-dir").unwrap_or("".into()), 119 | no_show: res.get("no-show").unwrap(), 120 | save_png: res.get("save-png").unwrap(), 121 | echo: res.get("echo").unwrap_or(false), 122 | term: res.get::("terminal").map(|s| s.to_string()), 123 | extension: res.get::("extension").unwrap(), 124 | }) 125 | } 126 | 127 | pub fn show(&self, fg: &mut Figure, filename: &str) 128 | { 129 | let out_path = Path::new(&self.output_dir).join(filename); 130 | self.term.as_ref().map(|t| { 131 | fg.set_terminal( 132 | &t, 133 | out_path.with_extension(&self.extension).to_str().unwrap(), 134 | ); 135 | }); 136 | if !self.no_show 137 | { 138 | fg.show().unwrap(); 139 | } 140 | if self.save_png 141 | { 142 | fg.save_to_png(out_path.with_extension("png").to_str().unwrap(), 800, 600) 143 | .unwrap(); 144 | } 145 | if self.echo 146 | { 147 | fg.echo_to_file(out_path.with_extension("gnuplot").to_str().unwrap()); 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /gnuplot/examples/dash_type.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | 5 | mod common; 6 | 7 | fn example(c: Common) 8 | { 9 | let x = 0..10; 10 | 11 | let mut fg = Figure::new(); 12 | 13 | let ax = fg.axes2d(); 14 | ax.set_title("Dash type", &[]); 15 | ax.set_legend(Graph(0.3), Graph(0.9), &[], &[]); 16 | for (i, &dt) in [Solid, SmallDot, Dot, Dash, DotDash, DotDotDash] 17 | .iter() 18 | .enumerate() 19 | { 20 | ax.lines( 21 | x.clone(), 22 | x.clone().map(|v| v * 2 + 2 * i), 23 | &[ 24 | LineWidth(2.), 25 | Color("black".into()), 26 | LineStyle(dt), 27 | Caption(&format!("{:?}", dt)), 28 | ], 29 | ); 30 | } 31 | 32 | c.show(&mut fg, "dash_type"); 33 | } 34 | 35 | fn main() 36 | { 37 | Common::new().map(|c| example(c)); 38 | } 39 | -------------------------------------------------------------------------------- /gnuplot/examples/example1.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | 4 | use gnuplot::*; 5 | use std::iter::repeat; 6 | 7 | mod common; 8 | 9 | fn example(c: Common) 10 | { 11 | let x = &[1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]; 12 | let x = x.iter2(); 13 | let y1: Vec = x 14 | .map(|&v| { 15 | let z = v - 4.0; 16 | z * z - 5.0 17 | }) 18 | .collect(); 19 | let y1 = y1.iter2(); 20 | let y2: Vec = x 21 | .map(|&v| { 22 | let z = v - 4.0; 23 | -z * z + 5.0 24 | }) 25 | .collect(); 26 | let y2 = y2.iter2(); 27 | let y3: Vec = x.map(|&v| v - 4.0).collect(); 28 | let y3 = y3.iter2(); 29 | let y4: Vec = x.map(|&v| 0.9 * v - 4.0).collect(); 30 | let y4 = y4.iter2(); 31 | let x_err = repeat(0.1f32); 32 | let y_err = repeat(0.2f32); 33 | 34 | let mut fg = Figure::new(); 35 | 36 | fg.axes2d() 37 | .set_size(0.75, 1.0) 38 | .set_title("Example Plot fg1.1", &[]) 39 | .set_x_ticks(Some((Fix(1.0), 1)), &[Mirror(false)], &[]) 40 | .set_y_ticks(Some((Fix(1.0), 1)), &[Mirror(false)], &[]) 41 | .set_legend( 42 | Graph(1.0), 43 | Graph(0.5), 44 | &[Placement(AlignLeft, AlignCenter)], 45 | &[TextAlign(AlignRight)], 46 | ) 47 | .set_border(true, &[Left, Bottom], &[LineWidth(2.0)]) 48 | .set_x_label("Abscissa", &[]) 49 | .set_y_label("Ordinate", &[]) 50 | .arrow( 51 | Axis(5.7912), 52 | Axis(2.7912), 53 | Axis(5.7912), 54 | Axis(1.7912), 55 | &[ 56 | ArrowType(Closed), 57 | ArrowSize(0.1), 58 | LineWidth(2.0), 59 | Color("black".into()), 60 | ], 61 | ) 62 | .label("Here", Axis(5.7912), Axis(3.1), &[TextAlign(AlignCenter)]) 63 | .fill_between( 64 | x, 65 | y1.map(|&y| y * 0.85 - 1.0), 66 | y1.map(|&y| y * 1.15 + 1.0), 67 | &[Color("#aaaaff".into())], 68 | ) 69 | .lines( 70 | x, 71 | y1, 72 | &[ 73 | Caption("(x - 4)^2 - 5"), 74 | LineWidth(1.5), 75 | Color("black".into()), 76 | ], 77 | ) 78 | .y_error_lines( 79 | x, 80 | y2, 81 | repeat(1.0f32), 82 | &[ 83 | Caption("-(x - 4)^2 + 5"), 84 | LineWidth(1.5), 85 | Color("red".into()), 86 | ], 87 | ) 88 | .lines_points( 89 | x, 90 | y3, 91 | &[ 92 | Caption("x - 4"), 93 | PointSymbol('t'), 94 | LineWidth(1.5), 95 | LineStyle(Dash), 96 | Color("#11ff11".into()), 97 | ], 98 | ); 99 | 100 | c.show(&mut fg, "example1_1"); 101 | 102 | let mut fg = Figure::new(); 103 | 104 | fg.axes2d() 105 | .set_pos_grid(2, 2, 0) 106 | .lines( 107 | x, 108 | y1, 109 | &[Caption("Lines"), LineWidth(3.0), Color("violet".into())], 110 | ) 111 | .set_title("Plot1 fg1.2", &[]); 112 | 113 | fg.axes2d() 114 | .set_pos_grid(2, 1, 1) 115 | .points( 116 | x, 117 | y2, 118 | &[ 119 | Caption("Points"), 120 | PointSymbol('D'), 121 | Color("#ffaa77".into()), 122 | PointSize(2.0), 123 | ], 124 | ) 125 | .set_title("Plot2", &[]); 126 | 127 | c.show(&mut fg, "example1_2"); 128 | 129 | let mut fg = Figure::new(); 130 | 131 | fg.axes2d().lines( 132 | x, 133 | y1, 134 | &[Caption("Lines"), LineWidth(3.0), Color("violet".into())], 135 | ); 136 | 137 | fg.axes2d() 138 | .set_pos(0.2, 0.4) 139 | .set_size(0.3, 0.6) 140 | .set_aspect_ratio(Fix(1.0)) 141 | .points( 142 | x, 143 | y2, 144 | &[Caption("Points"), PointSymbol('T'), Color("#ffaa77".into())], 145 | ) 146 | .set_title("Inset fg1.3", &[]); 147 | 148 | c.show(&mut fg, "example1_3"); 149 | 150 | let mut fg = Figure::new(); 151 | 152 | fg.axes2d() 153 | .lines( 154 | x, 155 | y1, 156 | &[Caption("Lines"), LineWidth(3.0), Color("violet".into())], 157 | ) 158 | .set_y_range(Fix(-30.0), Auto) 159 | .set_y_label("This axis is manually scaled on the low end", &[]) 160 | .set_title("Range fg1.4", &[]); 161 | 162 | c.show(&mut fg, "example1_4"); 163 | 164 | let mut fg = Figure::new(); 165 | 166 | fg.axes2d() 167 | .x_error_lines( 168 | x, 169 | y1, 170 | x_err.clone(), 171 | &[ 172 | Caption(r"x\_error\_lines"), 173 | LineWidth(2.0), 174 | PointSymbol('O'), 175 | Color("red".into()), 176 | ], 177 | ) 178 | .y_error_lines( 179 | x, 180 | y2, 181 | y_err.clone(), 182 | &[ 183 | Caption(r"y\_error\_lines"), 184 | LineWidth(2.0), 185 | PointSymbol('S'), 186 | Color("blue".into()), 187 | ], 188 | ) 189 | .x_error_bars( 190 | x, 191 | y3, 192 | x_err, 193 | &[ 194 | Caption(r"x\_error\_bars"), 195 | PointSymbol('T'), 196 | Color("cyan".into()), 197 | ], 198 | ) 199 | .y_error_bars( 200 | x, 201 | y4, 202 | y_err, 203 | &[ 204 | Caption(r"y\_error\_bars"), 205 | PointSymbol('R'), 206 | Color("green".into()), 207 | ], 208 | ) 209 | .set_title("Error fg1.5", &[]); 210 | 211 | c.show(&mut fg, "example1_5"); 212 | 213 | let mut fg = Figure::new(); 214 | 215 | fg.axes2d() 216 | .set_size(1.0, 0.8) 217 | .set_pos(0.0, 0.2) 218 | .fill_between( 219 | x, 220 | y1, 221 | y3, 222 | &[ 223 | Color("red".into()), 224 | FillAlpha(0.5), 225 | FillRegion(Above), 226 | Caption("A > B"), 227 | ], 228 | ) 229 | .fill_between( 230 | x, 231 | y1, 232 | y3, 233 | &[ 234 | Color("green".into()), 235 | FillAlpha(0.5), 236 | FillRegion(Below), 237 | Caption("A < B"), 238 | ], 239 | ) 240 | .fill_between( 241 | x, 242 | y2, 243 | y3, 244 | &[ 245 | Color("blue".into()), 246 | FillAlpha(0.5), 247 | FillRegion(Between), 248 | Caption("Between C and B"), 249 | ], 250 | ) 251 | .lines( 252 | x, 253 | y1, 254 | &[ 255 | Color("black".into()), 256 | LineWidth(2.0), 257 | LineStyle(Dash), 258 | Caption("A"), 259 | ], 260 | ) 261 | .lines( 262 | x, 263 | y2, 264 | &[Color("black".into()), LineWidth(2.0), Caption("C")], 265 | ) 266 | .lines( 267 | x, 268 | y3, 269 | &[ 270 | Color("black".into()), 271 | LineWidth(2.0), 272 | LineStyle(DotDotDash), 273 | Caption("B"), 274 | ], 275 | ) 276 | .set_title("Fill and legend fg1.6", &[]) 277 | .set_legend( 278 | Graph(0.5), 279 | Graph(-0.2), 280 | &[ 281 | Horizontal, 282 | Placement(AlignCenter, AlignTop), 283 | Title("Legend Title"), 284 | ], 285 | &[TextAlign(AlignRight)], 286 | ); 287 | 288 | c.show(&mut fg, "example1_6"); 289 | 290 | let mut fg = Figure::new(); 291 | 292 | fg.axes2d() 293 | .set_pos(0.1, 0.1) 294 | .set_size(0.8, 0.8) 295 | .lines( 296 | x, 297 | y1, 298 | &[ 299 | Caption("(x - 4)^2 - 5"), 300 | LineWidth(3.0), 301 | Color("violet".into()), 302 | LineStyle(DotDash), 303 | ], 304 | ) 305 | .points( 306 | x, 307 | y2, 308 | &[ 309 | Caption("-(x - 4)^2 + 5"), 310 | PointSymbol('S'), 311 | Color("#ffaa77".into()), 312 | ], 313 | ) 314 | .lines_points( 315 | x, 316 | y3, 317 | &[ 318 | Caption("x - 4"), 319 | PointSymbol('O'), 320 | Color("black".into()), 321 | LineStyle(SmallDot), 322 | ], 323 | ) 324 | .set_x_label( 325 | "X Label", 326 | &[Font("Arial", 24.0), TextColor("red".into()), Rotate(45.0)], 327 | ) 328 | .set_y_label("Y Label", &[Rotate(0.0)]) 329 | .set_title( 330 | "Goings nuts with the formatting fg1.7", 331 | &[Font("Times", 24.0), TextOffset(-10.0, 0.5)], 332 | ) 333 | .label( 334 | "Intersection", 335 | Axis(2.208), 336 | Axis(-1.791), 337 | &[ 338 | MarkerSymbol('*'), 339 | TextAlign(AlignCenter), 340 | TextOffset(0.0, -1.0), 341 | MarkerColor(RGBString("red")), 342 | MarkerSize(2.0), 343 | ], 344 | ); 345 | 346 | c.show(&mut fg, "example1_7"); 347 | } 348 | 349 | fn main() 350 | { 351 | Common::new().map(|c| example(c)); 352 | } 353 | -------------------------------------------------------------------------------- /gnuplot/examples/example2.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | 4 | use gnuplot::*; 5 | 6 | mod common; 7 | 8 | fn example(c: Common) 9 | { 10 | let x = &[1i32, 2, 3, 4, 5]; 11 | let x = x.iter2(); 12 | let y1: Vec = x.map(|&v| v * v).collect(); 13 | let y1 = y1.iter2(); 14 | 15 | let x2 = &[1i32, 4, 5]; 16 | let x2 = x2.iter2(); 17 | let y2: Vec = x2.map(|&v| v * v).collect(); 18 | let y2 = y2.iter2(); 19 | 20 | let x3 = &[1i32, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; 21 | let x3 = x3.iter2(); 22 | let y3: Vec = x3.map(|&v| v * v * v).collect(); 23 | let y3 = y3.iter2(); 24 | 25 | let zw = 16; 26 | let zh = 16; 27 | let mut z1 = Vec::with_capacity((zw * zh) as usize); 28 | for i in 0..zh 29 | { 30 | for j in 0..zw 31 | { 32 | let y = 8.0 * (i as f64) / zh as f64 - 4.0; 33 | let x = 8.0 * (j as f64) / zw as f64 - 4.0; 34 | z1.push(x + y); 35 | } 36 | } 37 | 38 | let mut fg = Figure::new(); 39 | 40 | fg.axes2d() 41 | .set_title("Arrows fg2.1", &[]) 42 | .lines( 43 | x, 44 | y1, 45 | &[LineWidth(3.0), Color("brown".into()), LineStyle(DotDash)], 46 | ) 47 | .arrow( 48 | Graph(0.5), 49 | Graph(1.0), 50 | Axis(1.0), 51 | Axis(1.0), 52 | &[ 53 | ArrowType(Filled), 54 | ArrowSize(0.1), 55 | LineStyle(DotDotDash), 56 | LineWidth(2.0), 57 | Color("red".into()), 58 | ], 59 | ) 60 | .arrow( 61 | Graph(0.5), 62 | Graph(1.0), 63 | Axis(3.0), 64 | Axis(9.0), 65 | &[ArrowType(Open), Color("green".into())], 66 | ); 67 | 68 | c.show(&mut fg, "example2_1"); 69 | 70 | let mut fg = Figure::new(); 71 | 72 | fg.axes2d() 73 | .set_title("Boxes fg2.2", &[]) 74 | .boxes( 75 | x2, 76 | y2, 77 | &[ 78 | LineWidth(2.0), 79 | Color("cyan".into()), 80 | BorderColor("blue".into()), 81 | LineStyle(DotDash), 82 | ], 83 | ) 84 | .boxes( 85 | x, 86 | y1, 87 | &[ 88 | LineWidth(2.0), 89 | Color("gray".into()), 90 | BorderColor("black".into()), 91 | BoxWidth([0.5, 0.4, 0.55, 0.7, 0.2].into()), 92 | ], 93 | ); 94 | 95 | c.show(&mut fg, "example2_2"); 96 | 97 | let mut fg = Figure::new(); 98 | 99 | fg.axes2d() 100 | .set_title("Axis Ticks fg2.3", &[]) 101 | .lines(x3, y3, &[LineWidth(2.0), Color("blue".into())]) 102 | .set_x_ticks_custom( 103 | x3.map(|&x| Major(x as f32, Fix("%.2f ms".to_string()))) 104 | .chain(x3.map(|&i| i as f32 + 0.5).map(|x| Minor(x))), 105 | &[MajorScale(2.0), MinorScale(0.5), OnAxis(true)], 106 | &[TextColor("blue".into()), TextAlign(AlignCenter)], 107 | ) 108 | .set_x_log(Some(10.0)) 109 | .set_y_ticks( 110 | Some((Fix(100.0), 1)), 111 | &[Mirror(false), Format("%.1f s")], 112 | &[], 113 | ); 114 | 115 | c.show(&mut fg, "example2_3"); 116 | 117 | let mut fg = Figure::new(); 118 | 119 | fg.axes2d() 120 | .set_title("Border, Axes fg2.4", &[]) 121 | .set_border(true, &[Left, Bottom], &[LineWidth(2.0)]) 122 | .set_x_ticks(Some((Fix(1.0), 1)), &[Mirror(false)], &[]) 123 | .set_y_ticks(Some((Fix(50.0), 0)), &[Mirror(false)], &[]) 124 | .lines(x3, y3, &[LineWidth(2.0), Color("blue".into())]) 125 | .set_x_axis(true, &[LineWidth(2.0), LineStyle(DotDotDash)]) 126 | .set_y_axis(true, &[LineWidth(2.0), Color("red".into())]); 127 | 128 | c.show(&mut fg, "example2_4"); 129 | 130 | let mut fg = Figure::new(); 131 | 132 | fg.axes2d().set_title("Image fg2.5", &[]).image( 133 | z1.iter(), 134 | zw, 135 | zh, 136 | Some((-4.0, -4.0, 4.0, 4.0)), 137 | &[], 138 | ); 139 | 140 | c.show(&mut fg, "example2_5"); 141 | 142 | let mut fg = Figure::new(); 143 | 144 | fg.axes2d() 145 | .set_title("Image without borders fg2.6", &[]) 146 | .set_border(false, &[], &[]) 147 | .set_x_ticks(None, &[], &[]) 148 | .set_y_ticks(None, &[], &[]) 149 | .image(z1.iter(), zw, zh, Some((-4.0, -4.0, 4.0, 4.0)), &[]); 150 | 151 | c.show(&mut fg, "example2_6"); 152 | 153 | let x4 = &[1f32, 10.0, 100.0]; 154 | let y4 = &[1f32, 3f32, 9f32]; 155 | 156 | let mut fg = Figure::new(); 157 | 158 | fg.axes2d() 159 | .set_title("Logarithmic fg2.7", &[]) 160 | .lines(x4.iter(), y4.iter(), &[]) 161 | .set_x_ticks(Some((Auto, 1)), &[], &[]) 162 | .set_y_ticks(Some((Auto, 1)), &[], &[]) 163 | .set_x_log(Some(10.0)) 164 | .set_y_log(Some(3.0)); 165 | 166 | c.show(&mut fg, "example2_7"); 167 | 168 | let mut fg = Figure::new(); 169 | 170 | fg.axes2d() 171 | .set_title("Axis Grid fg2.8", &[]) 172 | .lines(x3, y3, &[LineWidth(2.0), Color("blue".into())]) 173 | .set_y_ticks(Some((Auto, 2)), &[], &[]) 174 | .set_grid_options(true, &[LineStyle(DotDotDash), Color("black".into())]) 175 | .set_minor_grid_options(&[LineStyle(SmallDot), Color("red".into())]) 176 | .set_x_grid(true) 177 | .set_y_grid(true) 178 | .set_y_minor_grid(true); 179 | 180 | c.show(&mut fg, "example2_8"); 181 | } 182 | 183 | fn main() 184 | { 185 | Common::new().map(|c| example(c)); 186 | } 187 | -------------------------------------------------------------------------------- /gnuplot/examples/example3.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | 4 | use gnuplot::*; 5 | use std::vec::Vec; 6 | 7 | mod common; 8 | 9 | fn example(c: Common) 10 | { 11 | let w = 61; 12 | let h = 61; 13 | let mut z1 = Vec::with_capacity((w * h) as usize); 14 | for i in 0..h 15 | { 16 | for j in 0..w 17 | { 18 | let y = 8.0 * (i as f64) / h as f64 - 4.0; 19 | let x = 8.0 * (j as f64) / w as f64 - 4.0; 20 | z1.push(x.cos() * y.cos() / ((x * x + y * y).sqrt() + 1.0)); 21 | } 22 | } 23 | 24 | let mut fg = Figure::new(); 25 | 26 | fg.axes3d() 27 | .set_title("Surface fg3.1", &[]) 28 | .surface(z1.iter(), w, h, Some((-4.0, -4.0, 4.0, 4.0)), &[]) 29 | .set_x_label("X", &[]) 30 | .set_y_label("Y", &[]) 31 | .set_z_label("Z", &[]) 32 | .set_z_range(Fix(-1.0), Fix(1.0)) 33 | .set_z_ticks(Some((Fix(1.0), 1)), &[Mirror(false)], &[]) 34 | .set_view(45.0, 45.0); 35 | 36 | c.show(&mut fg, "example3_1"); 37 | 38 | let mut fg = Figure::new(); 39 | 40 | fg.axes3d() 41 | .set_title("Map fg3.2", &[]) 42 | .surface(z1.iter(), w, h, None, &[]) 43 | .set_x_label("X", &[]) 44 | .set_y_label("Y", &[]) 45 | .set_view_map(); 46 | 47 | c.show(&mut fg, "example3_2"); 48 | 49 | let mut fg = Figure::new(); 50 | 51 | fg.axes3d() 52 | .set_pos_grid(2, 2, 0) 53 | .set_title("Base fg3.3", &[]) 54 | .show_contours(true, false, Cubic(10), Fix(""), Auto) 55 | .surface(z1.iter(), w, h, Some((-4.0, -4.0, 4.0, 4.0)), &[]) 56 | .set_view(45.0, 45.0); 57 | 58 | fg.axes3d() 59 | .set_pos_grid(2, 2, 1) 60 | .set_title("Surface", &[]) 61 | .show_contours(false, true, Linear, Fix(""), Auto) 62 | .surface(z1.iter(), w, h, Some((-4.0, -4.0, 4.0, 4.0)), &[]) 63 | .set_view(45.0, 45.0); 64 | 65 | fg.axes3d() 66 | .set_pos_grid(2, 2, 2) 67 | .set_title("Both + Fix Levels", &[]) 68 | .show_contours(true, true, Linear, Fix("%f"), Fix(1)) 69 | .surface(z1.iter(), w, h, Some((-4.0, -4.0, 4.0, 4.0)), &[]) 70 | .set_view(45.0, 45.0); 71 | 72 | fg.axes3d() 73 | .set_pos_grid(2, 2, 3) 74 | .set_title("Custom Levels", &[]) 75 | .show_contours_custom(true, false, Linear, Fix(""), Some(0f32).iter()) 76 | .surface(z1.iter(), w, h, Some((-4.0, -4.0, 4.0, 4.0)), &[]) 77 | .set_view(45.0, 45.0); 78 | 79 | c.show(&mut fg, "example3_3"); 80 | } 81 | 82 | fn main() 83 | { 84 | Common::new().map(|c| example(c)); 85 | } 86 | -------------------------------------------------------------------------------- /gnuplot/examples/example4.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | 5 | mod common; 6 | 7 | fn example(c: Common) 8 | { 9 | let zw = 61; 10 | let zh = 61; 11 | let mut z1 = Vec::with_capacity((zw * zh) as usize); 12 | for i in 0..zh 13 | { 14 | for j in 0..zw 15 | { 16 | let y = 8.0 * (i as f64) / zh as f64 - 4.0; 17 | let x = 8.0 * (j as f64) / zw as f64 - 4.0; 18 | z1.push(x.cos() * y.cos() / ((x * x + y * y).sqrt() + 1.0)); 19 | } 20 | } 21 | 22 | let mut fg = Figure::new(); 23 | 24 | fg.axes2d() 25 | .set_title("Image fg4.1", &[]) 26 | .set_cb_range(Fix(-1.0), Fix(1.0)) 27 | .set_cb_ticks(Some((Fix(0.25), 1)), &[], &[]) 28 | .set_cb_label("Label", &[Rotate(0.0)]) 29 | .image(z1.iter(), zw, zh, Some((-4.0, -4.0, 4.0, 4.0)), &[]); 30 | 31 | c.show(&mut fg, "example4_1"); 32 | 33 | let mut fg = Figure::new(); 34 | 35 | fg.axes3d() 36 | .set_title("Surface fg4.2", &[]) 37 | .surface(z1.iter(), zw, zh, Some((-4.0, -4.0, 4.0, 4.0)), &[]) 38 | .set_x_label("X", &[]) 39 | .set_y_label("Y", &[]) 40 | .set_z_label("Z", &[]) 41 | .set_z_range(Fix(-1.0), Fix(1.0)) 42 | .set_z_ticks(Some((Fix(1.0), 1)), &[Mirror(false)], &[]) 43 | .set_cb_range(Fix(-1.0), Fix(1.0)) 44 | .set_view(45.0, 45.0); 45 | 46 | c.show(&mut fg, "example4_2"); 47 | 48 | let mut fg = Figure::new(); 49 | 50 | fg.axes3d() 51 | .set_title("Cube Helix Palette fg4.3", &[]) 52 | .surface(z1.iter(), zw, zh, Some((-4.0, -4.0, 4.0, 4.0)), &[]) 53 | .set_x_label("X", &[]) 54 | .set_y_label("Y", &[]) 55 | .set_z_label("Z", &[]) 56 | .set_z_range(Fix(-1.0), Fix(1.0)) 57 | .set_z_ticks(Some((Fix(1.0), 1)), &[Mirror(false)], &[]) 58 | .set_cb_range(Fix(-1.0), Fix(1.0)) 59 | .set_palette(HELIX) 60 | .set_view(45.0, 45.0); 61 | 62 | c.show(&mut fg, "example4_3"); 63 | 64 | let mut fg = Figure::new(); 65 | 66 | fg.axes3d() 67 | .set_title("Gray Palette fg4.4", &[]) 68 | .surface(z1.iter(), zw, zh, Some((-4.0, -4.0, 4.0, 4.0)), &[]) 69 | .set_x_label("X", &[]) 70 | .set_y_label("Y", &[]) 71 | .set_z_label("Z", &[]) 72 | .set_z_range(Fix(-1.0), Fix(1.0)) 73 | .set_z_ticks(Some((Fix(1.0), 1)), &[Mirror(false)], &[]) 74 | .set_palette(GRAY) 75 | .set_view(45.0, 45.0); 76 | 77 | c.show(&mut fg, "example4_4"); 78 | 79 | let mut fg = Figure::new(); 80 | 81 | fg.axes3d() 82 | .set_title("Black Body Palette fg4.5", &[]) 83 | .surface(z1.iter(), zw, zh, Some((-4.0, -4.0, 4.0, 4.0)), &[]) 84 | .set_x_label("X", &[]) 85 | .set_y_label("Y", &[]) 86 | .set_z_label("Z", &[]) 87 | .set_z_range(Fix(-1.0), Fix(1.0)) 88 | .set_z_ticks(Some((Fix(1.0), 1)), &[Mirror(false)], &[]) 89 | .set_palette(HOT) 90 | .set_view(45.0, 45.0); 91 | 92 | c.show(&mut fg, "example4_5"); 93 | 94 | let palette = vec![ 95 | (0.00, 1.0, 0.0, 0.0), 96 | (0.33, 1.0, 0.0, 0.0), 97 | (0.33, 0.0, 1.0, 0.0), 98 | (0.66, 0.0, 1.0, 0.0), 99 | (0.66, 0.0, 0.0, 1.0), 100 | (1.00, 0.0, 0.0, 1.0), 101 | ]; 102 | 103 | let mut fg = Figure::new(); 104 | 105 | fg.axes3d() 106 | .set_title("Custom Palette fg4.5", &[]) 107 | .surface(z1.iter(), zw, zh, Some((-4.0, -4.0, 4.0, 4.0)), &[]) 108 | .set_x_label("X", &[]) 109 | .set_y_label("Y", &[]) 110 | .set_z_label("Z", &[]) 111 | .set_z_range(Fix(-1.0), Fix(1.0)) 112 | .set_z_ticks(Some((Fix(1.0), 1)), &[Mirror(false)], &[]) 113 | .set_palette(Custom(&palette)) 114 | .set_view(45.0, 45.0); 115 | 116 | c.show(&mut fg, "example4_5"); 117 | } 118 | 119 | fn main() 120 | { 121 | Common::new().map(|c| example(c)); 122 | } 123 | -------------------------------------------------------------------------------- /gnuplot/examples/gif.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use gnuplot::*; 3 | use std::f32; 4 | 5 | fn main() 6 | { 7 | let mut fg = Figure::new(); 8 | let mut x = vec![]; 9 | for i in 0..100i32 10 | { 11 | x.push(i as f32 * 0.1 - 5.0); 12 | } 13 | 14 | let mut t = 0.0; 15 | fg.set_terminal("gif animate optimize delay 2 size 480,360", "gif.gif"); 16 | for i in 0..100 17 | { 18 | if i > 0 19 | { 20 | fg.new_page(); 21 | } 22 | let ax = fg.axes2d().set_y_range(Fix(-1.0), Fix(1.0)); 23 | ax.lines( 24 | x.iter(), 25 | x.iter() 26 | .map(|&x| (x + t as f32 * 0.1 * 2. * f32::consts::PI).sin()), 27 | &[Color("blue".into())], 28 | ); 29 | ax.lines( 30 | x.iter(), 31 | x.iter() 32 | .map(|&x| (x + t as f32 * 0.1 * 2. * f32::consts::PI).cos()), 33 | &[Color("red".into())], 34 | ); 35 | t += 0.1; 36 | } 37 | fg.echo_to_file("gif.gnuplot"); 38 | fg.show().unwrap(); 39 | } 40 | -------------------------------------------------------------------------------- /gnuplot/examples/inverse_api.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot as gp; 4 | use gnuplot::*; 5 | 6 | mod common; 7 | 8 | trait PlotElement 9 | { 10 | fn convert(&self, axes: &mut gp::Axes2D); 11 | fn to_axes2d(&self) -> Axes2D; 12 | } 13 | 14 | #[derive(Clone)] 15 | struct Lines 16 | { 17 | x: Vec, 18 | y: Vec, 19 | options: Vec>, 20 | } 21 | 22 | impl PlotElement for Lines 23 | { 24 | fn convert(&self, axes: &mut gp::Axes2D) 25 | { 26 | let mut options: Vec> = vec![]; 27 | for o in &self.options 28 | { 29 | options.push(match o 30 | { 31 | PointSymbol(v) => PointSymbol(*v), 32 | PointSize(v) => PointSize(*v), 33 | Caption(v) => Caption(&v), 34 | LineWidth(v) => LineWidth(*v), 35 | Color(v) => Color(v.to_ref()), 36 | BorderColor(v) => BorderColor(v.to_ref()), 37 | LineStyle(v) => LineStyle(*v), 38 | FillAlpha(v) => FillAlpha(*v), 39 | FillRegion(v) => FillRegion(*v), 40 | ArrowType(v) => ArrowType(*v), 41 | ArrowSize(v) => ArrowSize(*v), 42 | WhiskerBars(v) => WhiskerBars(*v), 43 | FillPattern(v) => FillPattern(*v), 44 | Axes(v1, v2) => Axes(*v1, *v2), 45 | BoxWidth(v) => BoxWidth(v.to_vec()), 46 | }); 47 | } 48 | 49 | axes.lines(self.x.clone(), self.y.clone(), &options); 50 | } 51 | 52 | fn to_axes2d(&self) -> Axes2D 53 | { 54 | Axes2D::new(vec![Box::new(self.clone())]) 55 | } 56 | } 57 | 58 | impl PlotElement for (T, T) 59 | { 60 | fn convert(&self, axes: &mut gp::Axes2D) 61 | { 62 | self.0.convert(axes); 63 | self.1.convert(axes); 64 | } 65 | 66 | fn to_axes2d(&self) -> Axes2D 67 | { 68 | Axes2D::new(vec![Box::new(self.0.clone()), Box::new(self.1.clone())]) 69 | } 70 | } 71 | 72 | fn lines<'l, Tx: IntoIterator, Ty: IntoIterator>(x: Tx, y: Ty) -> Lines 73 | { 74 | Lines { 75 | x: x.into_iter().collect(), 76 | y: y.into_iter().collect(), 77 | options: vec![], 78 | } 79 | } 80 | 81 | #[allow(dead_code)] 82 | impl Lines 83 | { 84 | fn show(&self) 85 | { 86 | self.to_axes2d().show(); 87 | } 88 | } 89 | 90 | struct Axes2D 91 | { 92 | plot_elements: Vec>, 93 | title: String, 94 | x_axis: Axis, 95 | } 96 | 97 | impl Axes2D 98 | { 99 | fn new(plot_elements: Vec>) -> Axes2D 100 | { 101 | Axes2D { 102 | plot_elements: plot_elements, 103 | title: "".into(), 104 | x_axis: axis(), 105 | } 106 | } 107 | 108 | fn title(&mut self, title: &str) -> &mut Axes2D 109 | { 110 | self.title = title.into(); 111 | self 112 | } 113 | 114 | fn x(&mut self, axis: &Axis) -> &mut Axes2D 115 | { 116 | self.x_axis = axis.clone(); 117 | self 118 | } 119 | 120 | fn show(&self) 121 | { 122 | let mut fg = Figure::new(); 123 | let mut ax = fg.axes2d(); 124 | ax.set_title(&self.title, &[]); 125 | ax.set_x_log(self.x_axis.log_scale); 126 | for pe in &self.plot_elements 127 | { 128 | pe.convert(&mut ax); 129 | } 130 | fg.show().unwrap(); 131 | } 132 | } 133 | 134 | #[derive(Clone)] 135 | struct Axis 136 | { 137 | log_scale: Option, 138 | } 139 | 140 | impl Axis 141 | { 142 | fn log_scale(&mut self, log_scale: Option) -> &mut Self 143 | { 144 | self.log_scale = log_scale; 145 | self 146 | } 147 | } 148 | 149 | fn axis() -> Axis 150 | { 151 | Axis { log_scale: None } 152 | } 153 | 154 | fn example(c: Common) 155 | { 156 | let z = (1..100).map(|z| z as f32 / 10.0); 157 | let x = z.clone().map(|z| z.cos()); 158 | let y = z.clone().map(|z| z.sin()); 159 | 160 | let mut fg = Figure::new(); 161 | 162 | fg.axes2d().lines(z.clone(), y.clone(), &[]); 163 | 164 | c.show(&mut fg, "inverse_api_old_1"); 165 | 166 | //~ fg.axes2d().set_title("Old API", &[]).lines( 167 | //~ z.clone(), 168 | //~ y.clone(), 169 | //~ &[LineWidth(2.), Color("#ffaa77".into())], 170 | //~ ).lines( 171 | //~ z.clone(), 172 | //~ x.clone(), 173 | //~ &[], 174 | //~ ); 175 | 176 | //~ c.show(&mut fg, "inverse_api_old_2"); 177 | 178 | //~ lines(z.clone(), y.clone()).show(); 179 | 180 | let mut axes = (lines(z.clone(), y.clone()), lines(z.clone(), x.clone())).to_axes2d(); 181 | axes.title("Test").x(axis().log_scale(Some(10.))); 182 | 183 | if !c.no_show 184 | { 185 | axes.show(); 186 | } 187 | } 188 | 189 | fn main() 190 | { 191 | Common::new().map(|c| example(c)); 192 | } 193 | -------------------------------------------------------------------------------- /gnuplot/examples/lines_3d.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | 5 | mod common; 6 | 7 | fn example(c: Common) 8 | { 9 | let z = (0..100).map(|z| z as f32 / 10.0); 10 | let x = z.clone().map(|z| z.cos()); 11 | let y = z.clone().map(|z| z.sin()); 12 | 13 | let mut fg = Figure::new(); 14 | 15 | fg.axes3d().set_title("3D lines", &[]).lines( 16 | x, 17 | y, 18 | z, 19 | &[PointSymbol('o'), Color("#ffaa77".into()), PointSize(2.0)], 20 | ); 21 | 22 | c.show(&mut fg, "lines_3d"); 23 | } 24 | 25 | fn main() 26 | { 27 | Common::new().map(|c| example(c)); 28 | } 29 | -------------------------------------------------------------------------------- /gnuplot/examples/lines_points_3d.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | 5 | mod common; 6 | 7 | fn example(c: Common) 8 | { 9 | let z = (0..100).map(|z| z as f32 / 10.0); 10 | let x = z.clone().map(|z| z.cos()); 11 | let y = z.clone().map(|z| z.sin()); 12 | 13 | let mut fg = Figure::new(); 14 | 15 | fg.axes3d() 16 | .set_title(r"3D lines + points", &[]) 17 | .lines_points( 18 | x, 19 | y, 20 | z, 21 | &[PointSymbol('o'), Color("#ffaa77".into()), PointSize(2.0)], 22 | ); 23 | 24 | c.show(&mut fg, "lines_points_3d"); 25 | } 26 | 27 | fn main() 28 | { 29 | Common::new().map(|c| example(c)); 30 | } 31 | -------------------------------------------------------------------------------- /gnuplot/examples/multiple_axes.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | 5 | mod common; 6 | 7 | fn example(c: Common) 8 | { 9 | let mut fg = Figure::new(); 10 | 11 | fg.axes2d() 12 | .set_title("Multiple axes", &[]) 13 | .lines_points( 14 | [0.0f32, 1.0, 2.0].iter(), 15 | [-1.0f32, 0.0, 1.0].iter(), 16 | &[Axes(X1, Y1), Color("blue".into())], 17 | ) 18 | .lines_points( 19 | [-0.6f32, 1.5, 2.5].iter(), 20 | [-5.0f32, 0.0, 5.0].iter(), 21 | &[Axes(X1, Y2), Color("red".into())], 22 | ) 23 | .set_y_ticks(Some((Auto, 0)), &[Mirror(false)], &[TextColor("blue".into())]) // Make Y1 not mirror. 24 | .set_y2_ticks(Some((Auto, 0)), &[Mirror(false)], &[TextColor("red".into())]) // Make Y2 not mirror, and visible. 25 | .set_y_label("Blue", &[TextColor("blue".into())]) 26 | .set_y2_label("Red", &[TextColor("red".into())]) 27 | .label("Blue Label", Axis(1.), Axis(0.), &[TextColor("blue".into()), TextAlign(AlignRight)]) 28 | .label("Red Label", Axis(2.0), Axis2(2.5), &[TextColor("red".into())]); 29 | 30 | c.show(&mut fg, "multiple_axes"); 31 | } 32 | 33 | fn main() 34 | { 35 | Common::new().map(|c| example(c)); 36 | } 37 | -------------------------------------------------------------------------------- /gnuplot/examples/multiplot_options.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::{MultiplotFillDirection::*, MultiplotFillOrder::*}; 4 | 5 | use gnuplot::*; 6 | 7 | mod common; 8 | 9 | fn example(c: Common) 10 | { 11 | let mut fg = Figure::new(); 12 | fg.set_multiplot_layout(2, 2) 13 | .set_title("Multiple parabolas") 14 | .set_scale(0.8, 0.8) 15 | .set_offset(0.0, 0.0) 16 | .set_multiplot_fill_order(RowsFirst, Upwards); 17 | 18 | fg.axes2d() 19 | .lines( 20 | &[-3., -2., -1., 0., 1., 2., 3.], 21 | &[9., 4., 1., 0., 1., 4., 9.], 22 | &[Caption("Parabola 1")], 23 | ) 24 | .set_x_label("X label", &[]) 25 | .set_title("Parabola 1", &[]) 26 | .label("Test 1", Axis(-3.), Axis(-3.), &[]) 27 | .label("Test 2", Axis(3.), Axis(3.), &[]) 28 | .arrow(Axis(-3.), Axis(-3.), Axis(3.), Axis(3.), &[]); 29 | 30 | fg.axes2d().lines( 31 | &[-3., -2., -1., 0., 1., 2., 3.], 32 | &[10., 5., 2., 0., 2., 5., 10.], 33 | &[Caption("Parabola 2")], 34 | ); 35 | 36 | fg.axes2d().lines( 37 | &[-3., -2., -1., 0., 1., 2., 3.], 38 | &[11., 6., 3., 0., 3., 6., 11.], 39 | &[Caption("Parabola 3")], 40 | ); 41 | 42 | c.show(&mut fg, "multiplot_options"); 43 | } 44 | 45 | fn main() 46 | { 47 | Common::new().map(|c| example(c)); 48 | } 49 | -------------------------------------------------------------------------------- /gnuplot/examples/patterns.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | 5 | mod common; 6 | 7 | fn example(c: Common) 8 | { 9 | let mut fg = Figure::new(); 10 | 11 | let ax = fg.axes2d(); 12 | ax.set_title("Patterns", &[]); 13 | ax.set_legend(Graph(1.), Graph(0.95), &[MaxRows(3)], &[]); 14 | ax.set_y_range(Auto, Fix(8.)); 15 | ax.set_box_width(0.5, false); 16 | for i in 0..=8 17 | { 18 | ax.boxes(&[i], &[5], &[FillPattern(Auto)]); 19 | } 20 | 21 | for (i, &pattern) in [ 22 | Pattern0, 23 | BigCrosses, 24 | SmallCrosses, 25 | Pattern3, 26 | BigBackSlashes, 27 | BigForwardSlashes, 28 | SmallForwardSlashes, 29 | SmallBackSlashes, 30 | Pattern8, 31 | ] 32 | .iter() 33 | .enumerate() 34 | { 35 | ax.boxes( 36 | &[i], 37 | &[-5], 38 | &[ 39 | FillPattern(Fix(pattern)), 40 | Caption(&format!("{:?}", pattern)), 41 | ], 42 | ); 43 | } 44 | 45 | c.show(&mut fg, "patterns"); 46 | } 47 | 48 | fn main() 49 | { 50 | Common::new().map(|c| example(c)); 51 | } 52 | -------------------------------------------------------------------------------- /gnuplot/examples/points_3d.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | 5 | mod common; 6 | 7 | fn example(c: Common) 8 | { 9 | let z = (0..100).map(|z| z as f32 / 10.0); 10 | let x = z.clone().map(|z| z.cos()); 11 | let y = z.clone().map(|z| z.sin()); 12 | 13 | let mut fg = Figure::new(); 14 | 15 | fg.axes3d().set_title("3D points", &[]).points( 16 | x, 17 | y, 18 | z, 19 | &[PointSymbol('o'), Color("#ffaa77".into()), PointSize(2.0)], 20 | ); 21 | 22 | c.show(&mut fg, "points_3d"); 23 | } 24 | 25 | fn main() 26 | { 27 | Common::new().map(|c| example(c)); 28 | } 29 | -------------------------------------------------------------------------------- /gnuplot/examples/polygons.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | 5 | mod common; 6 | 7 | fn example(c: Common) 8 | { 9 | let coords = [[0., 0.], [1., 1.], [2., 0.5], [2., -0.5], [1., -1.]]; 10 | 11 | let mut fg = Figure::new(); 12 | fg.set_title("Polygons"); 13 | 14 | let ax = fg.axes2d(); 15 | ax.polygon( 16 | coords.iter().map(|x| x[0]), 17 | coords.iter().map(|x| x[1]), 18 | &[], 19 | ); 20 | 21 | ax.polygon( 22 | coords.iter().map(|x| x[0] + 2.), 23 | coords.iter().map(|x| x[1]), 24 | &[FillAlpha(0.), BorderColor("black".into()), LineWidth(4.)], 25 | ); 26 | ax.polygon( 27 | coords.iter().map(|x| x[0]), 28 | coords.iter().map(|x| x[1] + 2.), 29 | &[ 30 | Color("#FF0000".into()), 31 | BorderColor("black".into()), 32 | LineWidth(4.), 33 | ], 34 | ); 35 | ax.polygon( 36 | coords.iter().map(|x| x[0] + 2.), 37 | coords.iter().map(|x| x[1] + 2.), 38 | &[ 39 | FillPattern(Fix(BigCrosses)), 40 | Color("#FF0000".into()), 41 | BorderColor("black".into()), 42 | LineWidth(4.), 43 | LineStyle(Dash), 44 | ], 45 | ); 46 | c.show(&mut fg, "polygons"); 47 | } 48 | 49 | fn main() 50 | { 51 | Common::new().map(|c| example(c)); 52 | } 53 | -------------------------------------------------------------------------------- /gnuplot/examples/readme_example.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | 4 | use gnuplot::*; 5 | 6 | mod common; 7 | 8 | fn example(c: Common) 9 | { 10 | let mut fg = Figure::new(); 11 | 12 | fg.axes2d() 13 | .set_title("A plot", &[]) 14 | .set_legend(Graph(0.5), Graph(0.9), &[], &[]) 15 | .set_x_label("x", &[]) 16 | .set_y_label("y^2", &[]) 17 | .lines( 18 | &[-3., -2., -1., 0., 1., 2., 3.], 19 | &[9., 4., 1., 0., 1., 4., 9.], 20 | &[Caption("Parabola")], 21 | ); 22 | 23 | c.show(&mut fg, "readme_example"); 24 | if !c.no_show 25 | { 26 | fg.set_terminal("pngcairo", "readme_example.png"); 27 | fg.show().unwrap(); 28 | } 29 | } 30 | 31 | fn main() 32 | { 33 | Common::new().map(|c| example(c)); 34 | } 35 | -------------------------------------------------------------------------------- /gnuplot/examples/text.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | 5 | mod common; 6 | 7 | fn example(c: Common) 8 | { 9 | let mut fg = Figure::new(); 10 | let _ax = fg 11 | .axes2d() 12 | .label( 13 | "multi\nline string", 14 | Coordinate::Graph(0.5), 15 | Coordinate::Graph(0.9), 16 | &[], 17 | ) 18 | .label( 19 | "x^2 x_2 {/Times*2 abc} \\{\\}\\^\\_", 20 | Coordinate::Graph(0.5), 21 | Coordinate::Graph(0.8), 22 | &[], 23 | ) 24 | .label( 25 | "Monospace", 26 | Coordinate::Graph(0.5), 27 | Coordinate::Graph(0.6), 28 | &[Font("Monospace", 32.)], 29 | ) 30 | .label( 31 | "Align Right", 32 | Coordinate::Graph(0.5), 33 | Coordinate::Graph(0.5), 34 | &[TextAlign(AlignRight)], 35 | ) 36 | .label( 37 | "Align Centre", 38 | Coordinate::Graph(0.5), 39 | Coordinate::Graph(0.4), 40 | &[TextAlign(AlignCenter)], 41 | ) 42 | .label( 43 | "~{Over}{Print}", // Why does gnuplot have this feature? 44 | Coordinate::Graph(0.5), 45 | Coordinate::Graph(0.3), 46 | &[TextAlign(AlignCenter)], 47 | ) 48 | .label( 49 | "Tab\tCharacter", // Strange rendering on this one 50 | Coordinate::Graph(0.5), 51 | Coordinate::Graph(0.2), 52 | &[TextAlign(AlignCenter)], 53 | ) 54 | .lines(&[-2., -2.], &[-3., 3.], &[]) 55 | .set_x_ticks(None, &[], &[]) 56 | .set_y_ticks(None, &[], &[]) 57 | .set_border(true, &[], &[]); 58 | 59 | c.show(&mut fg, "text"); 60 | } 61 | 62 | fn main() 63 | { 64 | Common::new().map(|c| example(c)); 65 | } 66 | -------------------------------------------------------------------------------- /gnuplot/examples/time.rs: -------------------------------------------------------------------------------- 1 | // This file is released into Public Domain. 2 | use crate::common::*; 3 | use gnuplot::*; 4 | use std::time::Duration; 5 | 6 | mod common; 7 | 8 | fn example(c: Common) 9 | { 10 | let x1 = &[ 11 | Duration::from_secs(0), 12 | Duration::from_secs(3600 * 12), 13 | Duration::from_secs(3600 * 24), 14 | Duration::from_secs(3600 * 36), 15 | ]; 16 | let x2 = &[ 17 | Duration::from_millis(0), 18 | Duration::from_millis(500), 19 | Duration::from_millis(1000), 20 | Duration::from_millis(1500), 21 | ]; 22 | let y = &[0i32, -1, 1, 0]; 23 | 24 | let mut fg = Figure::new(); 25 | 26 | fg.axes2d() 27 | .set_title("Time 1: Hours", &[]) 28 | .lines(x1, y, &[]) 29 | .set_x_ticks(Some((Auto, 1)), &[Format("%H hours")], &[]) 30 | .set_x_time(true); 31 | 32 | c.show(&mut fg, "time_1"); 33 | 34 | let mut fg = Figure::new(); 35 | fg.axes2d() 36 | .set_title("Time 2: Seconds", &[]) 37 | .lines(x2, y, &[]) 38 | .set_x_ticks(Some((Auto, 1)), &[Format("%.1S secs")], &[]) 39 | .set_x_time(true); 40 | 41 | c.show(&mut fg, "time_2"); 42 | } 43 | 44 | fn main() 45 | { 46 | Common::new().map(|c| example(c)); 47 | } 48 | -------------------------------------------------------------------------------- /gnuplot/examples/variable_color.rs: -------------------------------------------------------------------------------- 1 | use std::iter; 2 | 3 | // This file is released into Public Domain. 4 | use crate::common::*; 5 | use gnuplot::{palettes::MAGMA, *}; 6 | 7 | mod common; 8 | 9 | // https://github.com/gnuplot/gnuplot/blob/master/demo/candlesticks.dat 10 | #[rustfmt::skip] 11 | static CANDLESTICKS_STR: &str = 12 | "1 1.5 2 2.4 4 6. 13 | 2 1.5 3 3.5 4 5.5 14 | 3 4.5 5 5.5 6 6.5 15 | 4 3.7 4.5 5.0 5.5 6.1 16 | 5 3.1 3.5 4.2 5 6.1 17 | 6 1 4 5.0 6 9 18 | 7 4 4 4.8 6 6.1 19 | 8 4 5 5.1 6 6.1 20 | 9 1.5 2 2.4 3 3.5 21 | 10 2.7 3 3.5 4 4.3"; 22 | 23 | fn example(c: Common) 24 | { 25 | let data: Vec> = CANDLESTICKS_STR 26 | .split("\n") 27 | .map(|line| { 28 | line.split("\t") 29 | .map(|v| v.trim().parse::().unwrap()) 30 | .collect() 31 | }) 32 | .collect(); 33 | let extract_col = |i| data.iter().map(|l| l[i]).collect::>(); 34 | 35 | let d1 = extract_col(0); 36 | let d2 = extract_col(1); 37 | let d5 = extract_col(4); 38 | let d6 = extract_col(5); 39 | let row_index: Vec<_> = (1..=d1.len() as u8).collect(); 40 | let by3 = |x| (((x % 3.0) + 1.0) / 6.0); 41 | let by4 = |x| (((x % 4.0) + 1.0) / 7.0); 42 | 43 | let argb_formula = |x: &f64| { 44 | let a = 255.0 - 255.0 * (x - 5.5).abs() / 5.5; 45 | let r = x * 51.0 / 2.0; 46 | let g = (11.0 - x) * 51.0 / 2.0; 47 | let b = ((5.5 - x).abs() * 2.0 * 510.0 / 9.0).round(); 48 | (a as u8, r as u8, g as u8, b as u8) 49 | }; 50 | // Demo/test of variable color in many different plot styles 51 | // Inspired by https://gnuplot.sourceforge.net/demo_6.0/varcolor.html 52 | // 53 | // The loop is run four times with different color sets: each one sets all the elements of a given 54 | // plot to a different color, while making sure the colors align by x position: i.e. everything at x = 1 55 | // uses the first color, everything at x = 2 uses the second and so on. 56 | // 57 | // 58 | // The first color loop demonstrates usage of VariableIndexColor with indices to use gnuplot's default color styles, 59 | // but make them align for multiple plot items on the same axis. This is implicity constructed from a Vec using 60 | // the `IntoColor` trait but could equivalently be created explicitly using `Color(ColorType::VariableIndexColor(row_index.clone()))` 61 | // 62 | // The second color loop uses a `VariablePaletteColor`: this selects the color based on the current color palette and the 63 | // input value for each data point. The palette is scaled to the maximum value in the `Vec` passed 64 | // to the `VariablePaletteColor`. 65 | // 66 | // The third color loop uses an (implicit) `VariableARGBInteger`. The `Vec<(u8, u8, u8, u8)>` needed to construct the color 67 | // is calculated in this case by the `argb_formula()` closure. An explicit `VariableARGBInteger` could also be constructed using 68 | // `Color(ColorType::VariableARGBInteger(data)`. 69 | // As an alternative, `VariableRGBInteger` is also defined that takes a 3-tuple of u8, rather than 70 | // a 4 tuple. 71 | for (color, label) in [ 72 | (Color(row_index.clone().into()), "VariableIndexColor"), 73 | ( 74 | Color(VariablePaletteColor( 75 | row_index.iter().map(|v| *v as f64).collect(), 76 | )), 77 | "VariablePaletteColor", 78 | ), 79 | ( 80 | Color(d1.iter().map(argb_formula).collect::>().into()), 81 | "VariableARGBInteger", 82 | ), 83 | ] 84 | { 85 | let mut fg = Figure::new(); 86 | let ax = fg.axes2d(); 87 | ax.set_title( 88 | &format!("variable color boxerror, points, xyerrorbars, and boxxyerror.\nColor used is a {label}"), 89 | &[], 90 | ) 91 | .set_y_range(Fix(-4.0), Fix(11.5)) 92 | .set_box_width(0.5, true) 93 | .box_error_low_high( 94 | &d1, 95 | &d5, 96 | &d2, 97 | &d6, 98 | &[ 99 | color.clone(), 100 | FillAlpha(0.5), 101 | BorderColor(RGBString("black")), 102 | ], 103 | ) 104 | .points(&d1, iter::repeat(1), &[color.clone(), PointSymbol('D')]) 105 | .xy_error_bars( 106 | &d1, 107 | iter::repeat(8), 108 | d1.iter().map(by3), 109 | d1.iter().map(by4), 110 | &[color.clone()], 111 | ) 112 | .points( 113 | &d1, 114 | d2.iter().map(|v| -v / 2.0), 115 | &[color.clone(), PointSymbol('O'), PointSize(3.0)], 116 | ) 117 | .box_xy_error_delta( 118 | &d1, 119 | iter::repeat(10), 120 | d1.iter().map(by3), 121 | d1.iter().map(by4), 122 | &[color.clone(), BorderColor(RGBString("black"))], 123 | ); 124 | 125 | c.show(&mut fg, "variable_color"); 126 | } 127 | 128 | // ##################################################################### 129 | // The example below shows the same graphs as in the loop, but using a set of saved colormaps 130 | // similar to palette in gnuplot terms, but the a single (current) palette is applied to all plots by default. 131 | // By contrast, you can create multiple named colormaps. 132 | // 133 | // As with `VariablePaletteColor``, this Color takes a `Vec` that says which point in the colormap to use, 134 | // but it also takes a the name of the colormap from which to draw the colors. 135 | // 136 | // Note that the Color range appears to be shared across plots: i.e. if one plot has 137 | // color data (the `Vec`) in the range 0-1, and another in the range 1-100, all the 138 | // colors in the first plot will be right at the bottom end of its colormap, even if that's 139 | // a different colormap to the one used in the second plot. 140 | let mut fg = Figure::new(); 141 | let ax = fg.axes2d(); 142 | 143 | // First create the colormaps we will later refer to 144 | // MAGMA is one of the colormaps provided with rust gnuplot 145 | ax.create_colormap("magma", MAGMA); 146 | // HOT is one of the colormaps provided with rust gnuplot 147 | ax.create_colormap("hot", HOT); 148 | // ocean (green-blue-white) as per the gnuplot documentation 149 | ax.create_colormap("ocean", PaletteType::Formula(23, 28, 3)); 150 | 151 | let color_values: Vec = row_index.iter().map(|v| *v as f64).collect(); 152 | 153 | ax.set_title( 154 | &format!("variable color boxerror, points, xyerrorbars, and boxxyerror.\nColor used is a SavedColormap"), 155 | &[], 156 | ) 157 | .set_y_range(Fix(-4.0), Fix(11.5)) 158 | .set_box_width(0.8, false) 159 | .box_error_low_high( 160 | &d1, 161 | &d5, 162 | &d2, 163 | &d6, 164 | &[ 165 | Color(SavedColorMap("magma", color_values.clone())), 166 | FillAlpha(0.5), 167 | BorderColor(RGBString("black")), 168 | ], 169 | ) 170 | .points( 171 | &d1, 172 | iter::repeat(1), 173 | &[ 174 | Color(SavedColorMap( 175 | "hot", 176 | color_values.iter().map(|v| 11.0 - *v).collect(), 177 | )), 178 | PointSymbol('D'), 179 | ], 180 | ) 181 | .xy_error_bars( 182 | &d1, 183 | iter::repeat(8), 184 | d1.iter().map(by3), 185 | d1.iter().map(by4), 186 | &[Color(SavedColorMap("ocean", color_values.clone()))], 187 | ) 188 | .points( 189 | &d1, 190 | d2.iter().map(|v| -v / 2.0), 191 | &[ 192 | Color(SavedColorMap("magma", color_values.clone())), 193 | PointSymbol('O'), 194 | PointSize(3.0), 195 | ], 196 | ) 197 | .box_xy_error_delta( 198 | &d1, 199 | iter::repeat(10), 200 | d1.iter().map(by3), 201 | d1.iter().map(by4), 202 | &[ 203 | Color(SavedColorMap("hot", color_values.clone())), 204 | BorderColor(RGBString("black")), 205 | ], 206 | ); 207 | 208 | c.show(&mut fg, "variable_palette"); 209 | } 210 | 211 | fn main() 212 | { 213 | Common::new().map(|c| example(c)); 214 | } 215 | -------------------------------------------------------------------------------- /gnuplot/src/axes3d.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2014 by SiegeLord 2 | // 3 | // All rights reserved. Distributed under LGPL 3.0. For full terms see the file LICENSE. 4 | 5 | use crate::axes_common::*; 6 | use crate::datatype::*; 7 | use crate::options::*; 8 | use crate::util::OneWayOwned; 9 | use crate::writer::Writer; 10 | use std::borrow::Borrow; 11 | 12 | enum View 13 | { 14 | PitchYaw(f64, f64), 15 | Map, 16 | } 17 | 18 | impl View 19 | { 20 | fn write_out(&self, writer: &mut dyn Writer) 21 | { 22 | match self 23 | { 24 | Self::PitchYaw(pitch, yaw) => 25 | { 26 | writeln!(writer, "set view {:.12e},{:.12e}", pitch, yaw); 27 | } 28 | Self::Map => 29 | { 30 | writer.write_str("set view map\n"); 31 | } 32 | } 33 | } 34 | 35 | fn reset_state(&self, writer: &mut dyn Writer) 36 | { 37 | writer.write_str("unset view\n"); 38 | } 39 | } 40 | 41 | /// 3D axes that is used for drawing 3D plots 42 | pub struct Axes3D 43 | { 44 | common: AxesCommonData, 45 | z_axis: AxisData, 46 | contour_base: bool, 47 | contour_surface: bool, 48 | contour_auto: AutoOption, 49 | contour_levels: Option>, 50 | contour_style: ContourStyle, 51 | contour_label: AutoOption, 52 | view: Option, 53 | } 54 | 55 | impl Axes3D 56 | { 57 | pub(crate) fn new() -> Axes3D 58 | { 59 | Axes3D { 60 | common: AxesCommonData::new(), 61 | z_axis: AxisData::new(TickAxis::Z), 62 | contour_base: false, 63 | contour_surface: false, 64 | contour_auto: Auto, 65 | contour_levels: None, 66 | contour_style: Linear, 67 | contour_label: Auto, 68 | view: None, 69 | } 70 | } 71 | 72 | /// Draws a 3D surface from a rectangular array of data by connecting the individual datapoints with polygons. 73 | /// 74 | /// #Arguments: 75 | /// * `mat` - Row-major 2D array signifying the Z coordinate of the datapoints. The X and Y coordinates of the datapoints are determined automatically, 76 | /// and optionally scaled using the `dimensions` argument. 77 | /// * `num_rows` - Number of rows in the data array 78 | /// * `num_cols` - Number of columns in the data array 79 | /// * `dimensions` - Optional X and Y coordinates of the first and last data points (with the rest of the coordinates spaced evenly between). 80 | /// By default this will be `(0, 0)` and `(num_rows - 1, num_cols - 1)`. 81 | /// * `options` - Array of PlotOption controlling the appearance of the surface. Relevant options are: 82 | /// * `Caption` - Specifies the caption for this dataset. Use an empty string to hide it (default). 83 | pub fn surface<'l, T: DataType, X: IntoIterator>( 84 | &'l mut self, mat: X, num_rows: usize, num_cols: usize, 85 | dimensions: Option<(f64, f64, f64, f64)>, options: &[PlotOption<&str>], 86 | ) -> &'l mut Self 87 | { 88 | self.common.elems.push(PlotElement::new_plot_matrix( 89 | Pm3D, 90 | true, 91 | mat, 92 | num_rows, 93 | num_cols, 94 | dimensions, 95 | options.to_one_way_owned(), 96 | )); 97 | self 98 | } 99 | 100 | /// Plot a 3D scatter-plot with a point standing in for each data point 101 | /// # Arguments 102 | /// * `x` - x values 103 | /// * `y` - y values 104 | /// * `z` - z values 105 | /// * `options` - Array of PlotOption<&str> controlling the appearance of the plot element. The relevant options are: 106 | /// * `Caption` - Specifies the caption for this dataset. Use an empty string to hide it (default). 107 | /// * `PointSymbol` - Sets symbol for each point 108 | /// * `PointSize` - Sets the size of each point 109 | /// * `Color` - Sets the color 110 | pub fn points< 111 | 'l, 112 | Tx: DataType, 113 | X: IntoIterator, 114 | Ty: DataType, 115 | Y: IntoIterator, 116 | Tz: DataType, 117 | Z: IntoIterator, 118 | >( 119 | &'l mut self, x: X, y: Y, z: Z, options: &[PlotOption<&str>], 120 | ) -> &'l mut Self 121 | { 122 | let (data, num_rows, num_cols) = generate_data!(options, x, y, z); 123 | self.common.elems.push(PlotElement::new_plot( 124 | Points, data, num_rows, num_cols, options, 125 | )); 126 | self 127 | } 128 | 129 | /// Plot a 3D scatter-plot with lines connecting each data point 130 | /// # Arguments 131 | /// * `x` - x values 132 | /// * `y` - y values 133 | /// * `z` - z values 134 | /// * `options` - Array of PlotOption<&str> controlling the appearance of the plot element. The relevant options are: 135 | /// * `Caption` - Specifies the caption for this dataset. Use an empty string to hide it (default). 136 | /// * `PointSymbol` - Sets symbol for each point 137 | /// * `PointSize` - Sets the size of each point 138 | /// * `Color` - Sets the color 139 | pub fn lines< 140 | 'l, 141 | Tx: DataType, 142 | X: IntoIterator, 143 | Ty: DataType, 144 | Y: IntoIterator, 145 | Tz: DataType, 146 | Z: IntoIterator, 147 | >( 148 | &'l mut self, x: X, y: Y, z: Z, options: &[PlotOption<&str>], 149 | ) -> &'l mut Self 150 | { 151 | let (data, num_rows, num_cols) = generate_data!(options, x, y, z); 152 | self.common.elems.push(PlotElement::new_plot( 153 | Lines, data, num_rows, num_cols, options, 154 | )); 155 | self 156 | } 157 | 158 | /// A combination of lines and points methods (drawn in that order). 159 | /// # Arguments 160 | /// * `x` - x values 161 | /// * `y` - y values 162 | /// * `z` - z values 163 | /// * `options` - Array of PlotOption<&str> controlling the appearance of the plot element 164 | pub fn lines_points< 165 | 'l, 166 | Tx: DataType, 167 | X: IntoIterator, 168 | Ty: DataType, 169 | Y: IntoIterator, 170 | Tz: DataType, 171 | Z: IntoIterator, 172 | >( 173 | &'l mut self, x: X, y: Y, z: Z, options: &[PlotOption<&str>], 174 | ) -> &'l mut Self 175 | { 176 | let (data, num_rows, num_cols) = generate_data!(options, x, y, z); 177 | self.common.elems.push(PlotElement::new_plot( 178 | LinesPoints, 179 | data, 180 | num_rows, 181 | num_cols, 182 | options, 183 | )); 184 | self 185 | } 186 | 187 | /// Sets the 3D view. 188 | /// 189 | /// #Arguments: 190 | /// * `pitch` - Pitch, in degrees. Value of 0 is looking straight down on the XY plane, Z pointing out of the screen. 191 | /// * `yaw` - Yaw, in degrees. Value of 0 is looking at the XZ plane, Y point into the screen. 192 | pub fn set_view(&mut self, pitch: f64, yaw: f64) -> &mut Self 193 | { 194 | self.view = Some(View::PitchYaw(pitch, yaw)); 195 | self 196 | } 197 | 198 | /// Sets the view to be a map. Useful for images and contour plots. 199 | pub fn set_view_map(&mut self) -> &mut Self 200 | { 201 | self.view = Some(View::Map); 202 | self 203 | } 204 | 205 | /// Set the label for the Z axis 206 | /// 207 | /// # Arguments 208 | /// * `text` - Text of the label. Pass an empty string to hide the label 209 | /// * `options` - Array of LabelOption controlling the appearance of the label. Relevant options are: 210 | /// * `Offset` - Specifies the offset of the label 211 | /// * `Font` - Specifies the font of the label 212 | /// * `TextColor` - Specifies the color of the label 213 | /// * `Rotate` - Specifies the rotation of the label 214 | /// * `Align` - Specifies how to align the label 215 | pub fn set_z_label<'l>(&'l mut self, text: &str, options: &[LabelOption<&str>]) 216 | -> &'l mut Self 217 | { 218 | self.z_axis 219 | .label 220 | .set(text.into(), options.to_one_way_owned()); 221 | self 222 | } 223 | 224 | /// Sets the properties of x axis. 225 | /// 226 | /// # Arguments 227 | /// 228 | /// * `show` - Whether or not draw the axis 229 | /// * `options` - Array of PlotOption<&str> controlling the appearance of the axis. Relevant options are: 230 | /// * `Color` - Specifies the color of the border 231 | /// * `LineStyle` - Specifies the style of the border 232 | /// * `LineWidth` - Specifies the width of the border 233 | pub fn set_x_axis<'l>(&'l mut self, show: bool, options: &[PlotOption<&str>]) -> &'l mut Self 234 | { 235 | self.common.x_axis.show = show; 236 | self.common.x_axis.options = options.to_one_way_owned(); 237 | self 238 | } 239 | 240 | /// Like `set_x_axis` but for the y axis. 241 | pub fn set_y_axis<'l>(&'l mut self, show: bool, options: &[PlotOption<&str>]) -> &'l mut Self 242 | { 243 | self.common.y_axis.show = show; 244 | self.common.y_axis.options = options.to_one_way_owned(); 245 | self 246 | } 247 | 248 | /// Like `set_x_axis` but for the z axis. 249 | pub fn set_z_axis<'l>(&'l mut self, show: bool, options: &[PlotOption<&str>]) -> &'l mut Self 250 | { 251 | self.z_axis.show = show; 252 | self.z_axis.options = options.to_one_way_owned(); 253 | self 254 | } 255 | 256 | /// Like `set_x_ticks` but for the Z axis. 257 | pub fn set_z_ticks<'l>( 258 | &'l mut self, tick_placement: Option<(AutoOption, u32)>, 259 | tick_options: &[TickOption<&str>], label_options: &[LabelOption<&str>], 260 | ) -> &'l mut Self 261 | { 262 | self.z_axis.set_ticks( 263 | tick_placement, 264 | tick_options.to_one_way_owned(), 265 | label_options.to_one_way_owned(), 266 | ); 267 | self 268 | } 269 | 270 | /// Like `set_x_ticks_custom` but for the the Y axis. 271 | pub fn set_z_ticks_custom< 272 | 'l, 273 | T: DataType, 274 | S: ToString, 275 | TickT: Borrow>, 276 | TL: IntoIterator, 277 | >( 278 | &'l mut self, ticks: TL, tick_options: &[TickOption<&str>], 279 | label_options: &[LabelOption<&str>], 280 | ) -> &'l mut Self 281 | { 282 | self.z_axis.set_ticks_custom( 283 | ticks.into_iter().map(|e| e.borrow().to_one_way_owned()), 284 | tick_options.to_one_way_owned(), 285 | label_options.to_one_way_owned(), 286 | ); 287 | self 288 | } 289 | 290 | /// Set the range of values for the Z axis 291 | /// 292 | /// # Arguments 293 | /// * `min` - Minimum Z value 294 | /// * `max` - Maximum Z value 295 | pub fn set_z_range(&mut self, min: AutoOption, max: AutoOption) -> &mut Self 296 | { 297 | self.z_axis.set_range(min, max); 298 | self 299 | } 300 | 301 | /// Sets z axis to reverse. 302 | pub fn set_z_reverse(&mut self, reverse: bool) -> &mut Self 303 | { 304 | self.z_axis.set_reverse(reverse); 305 | self 306 | } 307 | 308 | /// Sets the Z axis be logarithmic. Note that the range must be non-negative for this to be valid. 309 | /// 310 | /// # Arguments 311 | /// * `base` - If Some, then specifies base of the logarithm, if None makes the axis not be logarithmic 312 | pub fn set_z_log(&mut self, base: Option) -> &mut Self 313 | { 314 | self.z_axis.set_log(base); 315 | self 316 | } 317 | 318 | /// Shows the grid on the Z axis. 319 | /// 320 | /// # Arguments 321 | /// * `show` - Whether to show the grid. 322 | pub fn set_z_grid(&mut self, show: bool) -> &mut Self 323 | { 324 | self.z_axis.set_grid(show); 325 | self 326 | } 327 | 328 | /// Sets the Z axis be time. Note that the range must be non-negative for this to be valid. 329 | /// 330 | /// If true, the axis is interpreted as seconds from the Unix epoch. Use the `Format` TickOption to 331 | /// specify the formatting of the ticks (see strftime format spec for valid values). 332 | /// 333 | /// # Arguments 334 | /// * `is_time` - Whether this axis is time or not. 335 | pub fn set_z_time(&mut self, is_time: bool) -> &mut Self 336 | { 337 | self.z_axis.set_time(is_time); 338 | self 339 | } 340 | 341 | /// Show contours (lines of equal Z value) at automatically determined levels. 342 | /// 343 | /// # Arguments 344 | /// * `base` - Show contours on the base of the plot (XY plane) 345 | /// * `surface` - Show the contours on the surface itself 346 | /// * `style` - Style of the contours 347 | /// * `label` - Auto sets the label automatically and enables the legend, Fix() allows you specify a format string (using C style formatting), 348 | /// otherwise an empty string disables the legend and labels. 349 | /// * `levels` - Auto picks some default number of levels, otherwise you can pass a set nominal number instead. The number is nominal as 350 | /// contours are placed at nice values of Z, and thus there may be fewer of them than this number. 351 | pub fn show_contours( 352 | &mut self, base: bool, surface: bool, style: ContourStyle, label: AutoOption<&str>, 353 | levels: AutoOption, 354 | ) -> &mut Self 355 | { 356 | self.contour_base = base; 357 | self.contour_surface = surface; 358 | self.contour_style = style; 359 | self.contour_auto = levels; 360 | self.contour_levels = None; 361 | self.contour_label = label.map(|l| l.to_string()); 362 | self 363 | } 364 | 365 | /// Show contours (lines of equal Z value) at specific levels. 366 | /// 367 | /// # Arguments 368 | /// * `base` - Show contours on the base of the plot (XY plane) 369 | /// * `surface` - Show the contours on the surface itself 370 | /// * `style` - Style of the contours 371 | /// * `label` - Auto sets the label automatically and enables the legend, Fix() allows you specify a format string (using C style formatting), 372 | /// otherwise an empty string disables the legend and labels. 373 | /// * `levels` - A set of levels. 374 | pub fn show_contours_custom>( 375 | &mut self, base: bool, surface: bool, style: ContourStyle, label: AutoOption<&str>, 376 | levels: TC, 377 | ) -> &mut Self 378 | { 379 | self.contour_base = base; 380 | self.contour_surface = surface; 381 | self.contour_style = style; 382 | self.contour_auto = Auto; 383 | self.contour_levels = Some(levels.into_iter().map(|l| l.get()).collect()); 384 | self.contour_label = label.map(|l| l.to_string()); 385 | self 386 | } 387 | 388 | pub(crate) fn reset_state(&self, writer: &mut dyn Writer) 389 | { 390 | self.common.reset_state(writer); 391 | if let Some(v) = self.view.as_ref() 392 | { 393 | v.reset_state(writer) 394 | }; 395 | } 396 | 397 | pub(crate) fn write_out( 398 | &self, data_directory: Option<&str>, w: &mut dyn Writer, auto_layout: bool, 399 | version: GnuplotVersion, 400 | ) 401 | { 402 | fn clamp(val: T, min: T, max: T) -> T 403 | { 404 | if val < min 405 | { 406 | min 407 | } 408 | else if val > max 409 | { 410 | max 411 | } 412 | else 413 | { 414 | val 415 | } 416 | } 417 | 418 | if self.contour_base || self.contour_surface 419 | { 420 | write!(w, "set contour "); 421 | write!( 422 | w, 423 | "{}", 424 | match (self.contour_base, self.contour_surface) 425 | { 426 | (true, false) => "base", 427 | (false, true) => "surface", 428 | (true, true) => "both", 429 | _ => unreachable!(), 430 | } 431 | ); 432 | writeln!(w); 433 | 434 | match self.contour_label 435 | { 436 | Auto => writeln!(w, "set clabel"), 437 | Fix(ref s) => 438 | { 439 | if s.is_empty() 440 | { 441 | writeln!(w, "unset clabel") 442 | } 443 | else 444 | { 445 | writeln!(w, r#"set clabel "{}""#, s) 446 | } 447 | } 448 | }; 449 | 450 | fn set_cntrparam(w: &mut dyn Writer, wr: F) 451 | { 452 | write!(w, "set cntrparam "); 453 | wr(w); 454 | writeln!(w); 455 | } 456 | 457 | set_cntrparam(w, |w| { 458 | write!( 459 | w, 460 | "{}", 461 | match self.contour_style 462 | { 463 | Linear => "linear ", 464 | Cubic(..) => "cubicspline", 465 | Spline(..) => "bspline", 466 | } 467 | ); 468 | }); 469 | 470 | set_cntrparam(w, |w| { 471 | let pt = match self.contour_style 472 | { 473 | Cubic(pt) => Some(pt), 474 | Spline(pt, _) => Some(pt), 475 | _ => None, 476 | }; 477 | 478 | if let Some(pt) = pt 479 | { 480 | write!(w, "points {}", clamp(pt, 2, 100)); 481 | }; 482 | }); 483 | 484 | set_cntrparam(w, |w| { 485 | let ord = match self.contour_style 486 | { 487 | Spline(_, ord) => Some(ord), 488 | _ => None, 489 | }; 490 | 491 | if let Some(ord) = ord 492 | { 493 | write!(w, "order {}", clamp(ord, 2, 10)); 494 | }; 495 | }); 496 | 497 | set_cntrparam(w, |w| { 498 | write!(w, "levels "); 499 | match self.contour_levels 500 | { 501 | Some(ref ls) => 502 | { 503 | write!(w, "discrete "); 504 | let mut left = ls.len(); 505 | for &l in ls.iter() 506 | { 507 | write!(w, "{:.12e}", l); 508 | if left > 1 509 | { 510 | write!(w, ","); 511 | } 512 | left -= 1; 513 | } 514 | } 515 | None => 516 | { 517 | match self.contour_auto 518 | { 519 | Auto => write!(w, "auto "), 520 | Fix(f) => write!(w, "{}", f), 521 | }; 522 | } 523 | }; 524 | }); 525 | } 526 | 527 | self.common.write_out_commands(w, auto_layout, version); 528 | self.z_axis.write_out_commands(w, version); 529 | let mut grid_axes = vec![]; 530 | if self.common.x_axis.grid 531 | { 532 | grid_axes.push(self.common.x_axis.axis); 533 | } 534 | if self.common.y_axis.grid 535 | { 536 | grid_axes.push(self.common.y_axis.axis); 537 | } 538 | if self.common.cb_axis.grid 539 | { 540 | grid_axes.push(self.common.cb_axis.axis); 541 | } 542 | if self.z_axis.grid 543 | { 544 | grid_axes.push(self.z_axis.axis); 545 | } 546 | if let Some(v) = self.view.as_ref() 547 | { 548 | v.write_out(w) 549 | }; 550 | self.common.write_grid_options(w, &grid_axes, version); 551 | self.common 552 | .write_out_elements("splot", data_directory, w, version); 553 | } 554 | } 555 | 556 | impl AxesCommonPrivate for Axes3D 557 | { 558 | fn get_common_data(&self) -> &AxesCommonData 559 | { 560 | &self.common 561 | } 562 | 563 | fn get_common_data_mut(&mut self) -> &mut AxesCommonData 564 | { 565 | &mut self.common 566 | } 567 | } 568 | 569 | impl AxesCommon for Axes3D {} 570 | -------------------------------------------------------------------------------- /gnuplot/src/color.rs: -------------------------------------------------------------------------------- 1 | pub use self::ColorType::*; 2 | use crate::util::OneWayOwned; 3 | use std::fmt::{Debug, Display}; 4 | 5 | pub type ColorIndex = u8; 6 | pub type ColorComponent = u8; 7 | pub type ColorInt = u32; 8 | pub type RGBInts = (ColorComponent, ColorComponent, ColorComponent); 9 | pub type ARGBInts = ( 10 | ColorComponent, 11 | ColorComponent, 12 | ColorComponent, 13 | ColorComponent, 14 | ); 15 | 16 | /// Option type (for plots, borders, and text) that allows the various different gnuplot 17 | /// color formats. The gnuplot [colorspec reference](http://gnuplot.info/docs_6.0/loc3640.html) 18 | /// also explains these. 19 | /// 20 | /// **NOTE**: Gnuplot interprets the alpha channel in an unusual way, where 0 is fully opaque and 21 | /// 255 is fully transparent. This wrapper inverts the meaning (as described below) to match the 22 | /// more common interpretation. 23 | /// 24 | /// There are many equivalent ways of specifying colors, and this allows the user to chose the most convenient. 25 | /// For example, all the following will produce the same blue color: 26 | /// `RGBColor("blue".into())`, `RGBColor("0x0000ff".into())`, `RGBColor("#0000ff".into())`, `RGBColor("0xff0000ff".into())`, 27 | /// `RGBColor("#ff0000ff".into())`, `RGBIntegerColor(0, 0, 255)`, `ARGBColor(255, 0, 0, 255)`, 28 | /// 29 | /// See example usages of these colors in `color.rs` and `variable_color.rs` in the 30 | /// [Examples folder](https://github.com/SiegeLord/RustGnuplot/tree/master/gnuplot/examples) on Github 31 | #[derive(Debug, Clone, PartialEq, PartialOrd)] 32 | pub enum ColorType 33 | { 34 | /// string (`&str` or `String`, but usually created with `&str`) in one of the following gnuplot-supported formats 35 | /// - colorname --- e.g. "blue" [See the gnuplot 36 | /// [list of colornames](http://gnuplot.info/docs_6.0/loc11229.html)] 37 | /// - 0xRRGGBB --- string containing hexadecimal constant 38 | /// - 0xAARRGGBB --- string containing hexadecimal constant 39 | /// - #RRGGBB --- string containing hexadecimal in x11 format 40 | /// - #AARRGGBB --- string containing hexadecimal in x11 format 41 | /// 42 | /// "#AARRGGBB" represents an RGB color with an alpha channel value in the high bits. 43 | /// An alpha value of 255 (FF) represents a fully opaque color; i.e., "#FFRRGGBB" is the same as "#RRGGBB". 44 | /// An alpha value of 0 represents full transparency. 45 | RGBString(T), 46 | /// tuple of u8 representing red, green and blue values as 0-255 47 | RGBInteger(ColorComponent, ColorComponent, ColorComponent), 48 | /// tuple of u8 representing alpha, red, green and blue values as 0-255. 49 | /// As with `RGBColor`, an alpha value of 255 (FF) represents a fully opaque color; 50 | /// an alpha value of 0 represents full transparency. 51 | ARGBInteger( 52 | ColorComponent, 53 | ColorComponent, 54 | ColorComponent, 55 | ColorComponent, 56 | ), 57 | /// Vector of tuples of `u8` (as per `RGBColor`), but instead of a single color for the whole 58 | /// plot, the vector should contain a separte color for each data point. 59 | VariableRGBInteger(Vec), 60 | /// Vector of tuples of `u8` (as per `ARGBColor`), but as with `VariableRGBColor`, a separate 61 | /// color value is given for each data point. 62 | VariableARGBInteger(Vec), 63 | /// Sets the color of the plot element to a value picked from the current palette (see 64 | /// [set_palette()](crate::AxesCommon::set_palette())). The value supplied to this color type 65 | /// selects the color within the color range of the palette: i.e. it if the color bar range had been 66 | /// set with `ax.set_cb_range(Fix(min), Fix(max))`, the value would be expected to be between 67 | /// `min` and `max`. 68 | /// 69 | /// Example of usage is give in the `color` example. 70 | /// 71 | /// Compare with [PaletteFracColor] 72 | PaletteFracColor(f64), 73 | /// Sets the color of the plot element to a value picked from the current palette (see 74 | /// [set_palette()](crate::AxesCommon::set_palette()) . The value supplied to this color type 75 | /// selects the color as a fraction of the current color range i.e. it is expected to be 76 | /// between `0` and `1`. 77 | /// 78 | /// Example of usage is give in the `color` example. 79 | /// 80 | /// Comparing with [PaletteCBColor]: given the following code 81 | /// ``` 82 | /// use gnuplot::{PaletteCBColor, PaletteFracColor, Fix, Figure, AxesCommon, Color}; 83 | ///# let min = -5.0; // or any value 84 | ///# let max = 12.0; // or any value 85 | /// 86 | ///# let frac = 0.5; // or any value 0.0 <= frac <= 1.0 87 | ///# let x = [1,2,3]; 88 | ///# let y = [4,5,6]; 89 | /// assert!(frac >= 0.0); 90 | /// assert!(frac <= 1.0); 91 | /// 92 | /// let mut fg = Figure::new(); 93 | /// let ax = fg.axes2d(); 94 | /// ax.set_cb_range(Fix(min), Fix(max)); 95 | /// let col1 = Color(PaletteFracColor(frac)); 96 | /// let cb_range = max - min; 97 | /// let col2 = Color(PaletteCBColor(min + (frac * cb_range))); 98 | /// ax.lines(x, y, &[col1]); 99 | /// ax.lines(x, y, &[col2]); 100 | /// ``` 101 | /// the two lines should give the same color for any values of `max` and `min`, and `0 <= frac <= 1`. 102 | PaletteCBColor(f64), 103 | /// Vector of `f64` values which act as indexes into the current palette to set the color of 104 | /// each data point. These variable values work in the same was as the single fixed value supplied 105 | /// to a [PaletteCBColor] 106 | VariablePaletteColor(Vec), 107 | /// Similar to `VariablePaletteColor` in that it takes a `Vec` to set the indexes into the 108 | /// color map for each data point, but in addition to the color data it takes a string hold the name 109 | /// of the colormap to use. This should have been previously created in the workspace using the 110 | /// [create_colormap()](crate::AxesCommon::create_colormap) function. 111 | SavedColorMap(T, Vec), 112 | /// Set the color of all elements of the plot to the `n`th color in the current gnuplot color cycle. 113 | Index(ColorIndex), 114 | /// A color type that sets the color per element using a index `n` which represents the `n`th 115 | /// color in the current gnuplot color scheme. In gnuplot this is the last element in the plot command, 116 | /// in Rust gnuplot, the color type takes a vector of u8, where each index is treated the same as the 117 | /// fixed `IndexColor`. 118 | /// This is useful for setting bars/boxes etc to be 119 | /// the same color from multiple plot commands. The `variable_color` example has examples of this usage. 120 | VariableIndex(Vec), 121 | /// Set the color of the plot to the current background color. 122 | Background, 123 | /// Fixed black color 124 | Black, 125 | } 126 | 127 | impl ColorType 128 | { 129 | /// Returns the gnuplot string that will produce the requested color 130 | pub fn command(&self) -> String 131 | { 132 | match self 133 | { 134 | RGBString(s) => format!(r#"rgb "{}""#, from_string(s.to_string())), 135 | RGBInteger(r, g, b) => format!(r#"rgb {}"#, from_argb(255, *r, *g, *b)), 136 | ARGBInteger(a, r, g, b) => format!(r#"rgb {}"#, from_argb(*a, *r, *g, *b)), 137 | VariableRGBInteger(_) => "rgb variable".into(), 138 | VariableARGBInteger(_) => "rgb variable".into(), 139 | PaletteFracColor(v) => format!("palette frac {v}"), 140 | PaletteCBColor(v) => format!("palette cb {v}"), 141 | VariablePaletteColor(_) => "palette z".into(), 142 | SavedColorMap(s, _) => format!("palette {s}"), 143 | VariableIndex(_) => "variable".into(), 144 | Background => "bgnd".into(), 145 | Index(n) => format!("{}", n), 146 | Black => "black".into(), 147 | } 148 | } 149 | 150 | pub fn data(&self) -> Vec 151 | { 152 | match self 153 | { 154 | VariableRGBInteger(items) => items 155 | .iter() 156 | .map(|(r, g, b)| from_argb(255, *r, *g, *b) as f64) 157 | .collect(), 158 | VariableARGBInteger(items) => items 159 | .iter() 160 | .map(|(a, r, g, b)| from_argb(*a, *r, *g, *b) as f64) 161 | .collect(), 162 | VariablePaletteColor(items) => items.clone(), 163 | SavedColorMap(_, items) => items.clone(), 164 | VariableIndex(items) => items.iter().map(|v| *v as f64).collect(), 165 | c => panic!("data() called on non-variable color type: {:?}", *c), 166 | } 167 | } 168 | 169 | pub fn is_variable(&self) -> bool 170 | { 171 | matches!( 172 | self, 173 | VariableRGBInteger(_) 174 | | VariableARGBInteger(_) 175 | | VariableIndex(_) 176 | | VariablePaletteColor(_) 177 | | SavedColorMap(_, _) 178 | ) 179 | } 180 | 181 | pub fn has_alpha(&self) -> bool 182 | { 183 | match self 184 | { 185 | RGBString(s) => 186 | { 187 | let s = s.to_string(); 188 | s.starts_with("0x") && s.len() == 10 || s.starts_with("#") && s.len() == 9 189 | } 190 | ARGBInteger(_, _, _, _) | VariableARGBInteger(_) => true, 191 | _ => false, 192 | } 193 | } 194 | } 195 | 196 | fn from_argb(a: ColorComponent, r: ColorComponent, g: ColorComponent, b: ColorComponent) 197 | -> ColorInt 198 | { 199 | ((255 - a as ColorInt) << 24) 200 | + ((r as ColorInt) << 16) 201 | + ((g as ColorInt) << 8) 202 | + (b as ColorInt) 203 | } 204 | 205 | fn from_string(argb: String) -> String 206 | { 207 | if let Some(trimmed_argb) = argb.strip_prefix("0x").or_else(|| argb.strip_prefix("#")) 208 | { 209 | if trimmed_argb.len() == 8 210 | { 211 | if let Ok(argb_int) = ColorInt::from_str_radix(trimmed_argb, 16) 212 | { 213 | let a = 255 - ((argb_int >> 24) & 0xff); 214 | let argb_int = (a << 24) + (argb_int & 0xffffff); 215 | format!("#{:08x}", argb_int) 216 | } 217 | else 218 | { 219 | // Let gnuplot sort it out. 220 | argb 221 | } 222 | } 223 | else 224 | { 225 | argb 226 | } 227 | } 228 | else 229 | { 230 | argb 231 | } 232 | } 233 | 234 | fn float_color_to_int(v: f64) -> Result 235 | { 236 | if !(0.0..=1.0).contains(&v) 237 | { 238 | Err(format!( 239 | "Float value must be greater than zero and less than one. Actual value: {}", 240 | v 241 | )) 242 | } 243 | else 244 | { 245 | Ok(((v * 255.0).round()) as u8) 246 | } 247 | } 248 | 249 | /// Converts a set of `f64` red, green and blue values in the range `0 <= x <= 1` to a 3-tuple of `u8` suitable for use as 250 | /// an [RGBInteger] 251 | /// 252 | /// Returns an error String if any of the arguments are not in the range `0 <= x <= 1` 253 | /// 254 | /// Ses also [floats_to_argb] 255 | /// 256 | /// # Arguments 257 | /// * r - red. 0: no red, 1: fully red 258 | /// * g - green. 0: no green, 1: fully green 259 | /// * b - blue. 0: no blue, 1: fully blue 260 | fn floats_to_rgb(r: f64, g: f64, b: f64) -> Result 261 | { 262 | Ok(( 263 | float_color_to_int(r)?, 264 | float_color_to_int(g)?, 265 | float_color_to_int(b)?, 266 | )) 267 | } 268 | 269 | /// Converts a set of `f64` red, green and blue values in the range `0 <= x <= 1` to a 3-tuple of `u8` suitable for use as 270 | /// an [ARGBInteger] 271 | /// 272 | /// Returns an error String if any of the arguments are not in the range `0 <= x <= 1` 273 | /// 274 | /// Ses also [floats_to_rgb] 275 | /// 276 | /// # Arguments 277 | /// * a - alpha (transparency) value. 0: completely opaque, 1: completely transparent. 278 | /// * r - red. 0: no red, 1: fully red 279 | /// * g - green. 0: no green, 1: fully green 280 | /// * b - blue. 0: no blue, 1: fully blue 281 | fn floats_to_argb(a: f64, r: f64, g: f64, b: f64) -> Result 282 | { 283 | Ok(( 284 | float_color_to_int(a)?, 285 | float_color_to_int(r)?, 286 | float_color_to_int(g)?, 287 | float_color_to_int(b)?, 288 | )) 289 | } 290 | 291 | impl<'l> From<&'l str> for ColorType 292 | { 293 | /// Converts `&str` into [RGBString] 294 | fn from(value: &'l str) -> Self 295 | { 296 | ColorType::RGBString(String::from(value)) 297 | } 298 | } 299 | 300 | impl<'l> From for ColorType 301 | { 302 | /// Converts `String` into [RGBString] 303 | fn from(value: String) -> Self 304 | { 305 | ColorType::RGBString(value) 306 | } 307 | } 308 | 309 | impl<'l> From<&'l str> for ColorType<&'l str> 310 | { 311 | /// Converts `&str` into [RGBString] 312 | fn from(value: &'l str) -> Self 313 | { 314 | ColorType::RGBString(value) 315 | } 316 | } 317 | 318 | impl From for ColorType 319 | { 320 | /// Converts `(u8, u8, u8, u8)` into [ARGBInteger] 321 | fn from(value: ARGBInts) -> Self 322 | { 323 | ColorType::ARGBInteger(value.0, value.1, value.2, value.3) 324 | } 325 | } 326 | 327 | impl From for ColorType 328 | { 329 | /// Converts `(u8, u8, u8)` into [RGBInteger] 330 | fn from(value: RGBInts) -> Self 331 | { 332 | ColorType::RGBInteger(value.0, value.1, value.2) 333 | } 334 | } 335 | 336 | impl TryFrom<(f64, f64, f64)> for ColorType 337 | { 338 | type Error = String; 339 | /// Converts `(f64, f64, f64)` into [RGBInteger]. 340 | /// Returns an error unless all values are in the range `0 <= v <= 1`. 341 | fn try_from(value: (f64, f64, f64)) -> Result 342 | { 343 | let ints = floats_to_rgb(value.0, value.1, value.2)?; 344 | Ok(ColorType::RGBInteger(ints.0, ints.1, ints.2)) 345 | } 346 | } 347 | 348 | impl TryFrom<(f64, f64, f64, f64)> for ColorType 349 | { 350 | type Error = String; 351 | /// Converts `(f64, f64, f64, f64)` into [ARGBInteger]. 352 | /// Returns an error unless all values are in the range `0 <= v <= 1`. 353 | fn try_from(value: (f64, f64, f64, f64)) -> Result 354 | { 355 | let ints = floats_to_argb(value.0, value.1, value.2, value.3)?; 356 | Ok(ColorType::ARGBInteger(ints.0, ints.1, ints.2, ints.3)) 357 | } 358 | } 359 | 360 | impl From> for ColorType 361 | { 362 | /// Converts `Vec<(u8, u8, u8)>` into [VariableRGBInteger] 363 | fn from(value: Vec) -> Self 364 | { 365 | ColorType::VariableRGBInteger(value) 366 | } 367 | } 368 | 369 | impl From> for ColorType 370 | { 371 | /// Converts `Vec<(u8, u8, u8, u8)>` into [VariableARGBInteger] 372 | fn from(value: Vec) -> Self 373 | { 374 | ColorType::VariableARGBInteger(value) 375 | } 376 | } 377 | 378 | impl From for ColorType 379 | { 380 | /// Converts `u8` into [Index] 381 | fn from(value: ColorIndex) -> Self 382 | { 383 | ColorType::Index(value) 384 | } 385 | } 386 | 387 | impl From> for ColorType 388 | { 389 | /// Converts `Vec` into [VariableIndex] 390 | fn from(value: Vec) -> Self 391 | { 392 | ColorType::VariableIndex(value) 393 | } 394 | } 395 | 396 | impl OneWayOwned for ColorType 397 | { 398 | type Output = ColorType; 399 | 400 | fn to_one_way_owned(&self) -> ColorType 401 | { 402 | match self 403 | { 404 | RGBString(s) => RGBString(s.to_string()), 405 | RGBInteger(r, g, b) => RGBInteger(*r, *g, *b), 406 | VariableRGBInteger(d) => VariableRGBInteger(d.clone()), 407 | PaletteFracColor(v) => PaletteFracColor(*v), 408 | PaletteCBColor(v) => PaletteCBColor(*v), 409 | VariablePaletteColor(d) => VariablePaletteColor(d.clone()), 410 | SavedColorMap(s, d) => SavedColorMap(s.to_string(), d.clone()), 411 | VariableIndex(d) => VariableIndex(d.clone()), 412 | Background => Background, 413 | Index(n) => Index(*n), 414 | Black => Black, 415 | ARGBInteger(a, r, g, b) => ARGBInteger(*a, *r, *g, *b), 416 | VariableARGBInteger(d) => VariableARGBInteger(d.clone()), 417 | } 418 | } 419 | } 420 | 421 | impl ColorType 422 | { 423 | pub fn to_ref(&self) -> ColorType<&str> 424 | { 425 | match self 426 | { 427 | RGBString(s) => RGBString(s), 428 | RGBInteger(r, g, b) => RGBInteger(*r, *g, *b), 429 | VariableRGBInteger(d) => VariableRGBInteger(d.to_vec()), 430 | VariableARGBInteger(d) => VariableARGBInteger(d.to_vec()), 431 | PaletteFracColor(v) => PaletteFracColor(*v), 432 | PaletteCBColor(v) => PaletteCBColor(*v), 433 | VariablePaletteColor(d) => VariablePaletteColor(d.to_vec()), 434 | SavedColorMap(s, d) => SavedColorMap(s, d.to_vec()), 435 | VariableIndex(d) => VariableIndex(d.to_vec()), 436 | Background => Background, 437 | Index(n) => Index(*n), 438 | Black => Black, 439 | ARGBInteger(a, r, g, b) => ARGBInteger(*a, *r, *g, *b), 440 | } 441 | } 442 | } 443 | -------------------------------------------------------------------------------- /gnuplot/src/coordinates.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2014 by SiegeLord 2 | // 3 | // All rights reserved. Distributed under LGPL 3.0. For full terms see the file LICENSE. 4 | 5 | pub use self::Coordinate::*; 6 | use std::fmt; 7 | 8 | /// Specifies how to interpret the coordinate passed to a plotting command 9 | #[derive(Copy, Clone)] 10 | pub enum Coordinate 11 | { 12 | /// Coordinates are done relative to a graph (i.e. an axis set). (0, 0) is the bottom left corner and (1, 1) is the top right corner. 13 | /// You'd use this to place labels and other objects so that they remain in the same place relative to the graph no matter what you have plotted. 14 | Graph(f64), 15 | /// Coordinates match those on the axes. You'd use this to place labels and other objects relative to regions of interest in the graph (e.g. labeling the peak of a function) 16 | Axis(f64), 17 | /// Coordinates match those on the secondary axes. You'd use this to place labels and other objects relative to regions of interest in the graph (e.g. labeling the peak of a function) 18 | Axis2(f64), 19 | } 20 | 21 | impl fmt::Display for Coordinate 22 | { 23 | fn fmt(&self, buf: &mut fmt::Formatter) -> fmt::Result 24 | { 25 | let (name, x) = match *self 26 | { 27 | Graph(x) => (" graph ", x), 28 | Axis(x) => (" first ", x), 29 | Axis2(x) => (" second ", x), 30 | }; 31 | write!(buf, "{}{:.16e}", name, x) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /gnuplot/src/datatype.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2014 by SiegeLord 2 | // 3 | // All rights reserved. Distributed under LGPL 3.0. For full terms see the file LICENSE. 4 | 5 | use std::time::Duration; 6 | 7 | pub trait DataType: Clone 8 | { 9 | fn get(&self) -> f64; 10 | } 11 | 12 | macro_rules! impl_data_type { 13 | ($T:ty) => { 14 | impl<'l> DataType for &'l $T 15 | { 16 | fn get(&self) -> f64 17 | { 18 | **self as f64 19 | } 20 | } 21 | }; 22 | } 23 | 24 | macro_rules! impl_data_type_ref { 25 | ($T:ty) => { 26 | impl DataType for $T 27 | { 28 | fn get(&self) -> f64 29 | { 30 | *self as f64 31 | } 32 | } 33 | }; 34 | } 35 | 36 | impl_data_type!(u8); 37 | impl_data_type!(u16); 38 | impl_data_type!(u32); 39 | impl_data_type!(u64); 40 | impl_data_type!(usize); 41 | 42 | impl_data_type!(i8); 43 | impl_data_type!(i16); 44 | impl_data_type!(i32); 45 | impl_data_type!(i64); 46 | impl_data_type!(isize); 47 | 48 | impl_data_type!(f32); 49 | impl_data_type!(f64); 50 | 51 | impl_data_type_ref!(u8); 52 | impl_data_type_ref!(u16); 53 | impl_data_type_ref!(u32); 54 | impl_data_type_ref!(u64); 55 | impl_data_type_ref!(usize); 56 | 57 | impl_data_type_ref!(i8); 58 | impl_data_type_ref!(i16); 59 | impl_data_type_ref!(i32); 60 | impl_data_type_ref!(i64); 61 | impl_data_type_ref!(isize); 62 | 63 | impl_data_type_ref!(f32); 64 | impl_data_type_ref!(f64); 65 | 66 | impl DataType for Duration 67 | { 68 | fn get(&self) -> f64 69 | { 70 | // GnuPlot can't handle precision lower than milliseconds. 71 | self.as_secs() as f64 + self.subsec_millis() as f64 / 1000.0 72 | } 73 | } 74 | 75 | impl<'l> DataType for &'l Duration 76 | { 77 | fn get(&self) -> f64 78 | { 79 | // GnuPlot can't handle precision lower than milliseconds. 80 | self.as_secs() as f64 + self.subsec_millis() as f64 / 1000.0 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /gnuplot/src/error_types.rs: -------------------------------------------------------------------------------- 1 | use std::error; 2 | use std::fmt; 3 | use std::io; 4 | 5 | pub struct GnuplotInitError 6 | { 7 | inner: Box, 8 | } 9 | 10 | impl From for GnuplotInitError 11 | { 12 | fn from(error: io::Error) -> Self 13 | { 14 | GnuplotInitError { 15 | inner: Box::new(error), 16 | } 17 | } 18 | } 19 | 20 | impl fmt::Display for GnuplotInitError 21 | { 22 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result 23 | { 24 | write!( 25 | f, 26 | "Couldn't spawn gnuplot. Make sure it is installed and available in PATH.\nCause: {}", 27 | self.inner 28 | ) 29 | } 30 | } 31 | 32 | impl fmt::Debug for GnuplotInitError 33 | { 34 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result 35 | { 36 | write!(f, "{}", self) 37 | } 38 | } 39 | 40 | impl error::Error for GnuplotInitError 41 | { 42 | fn source(&self) -> Option<&(dyn error::Error + 'static)> 43 | { 44 | Some(&*self.inner) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /gnuplot/src/figure.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2014 by SiegeLord 2 | // 3 | // All rights reserved. Distributed under LGPL 3.0. For full terms see the file LICENSE. 4 | 5 | use crate::error_types::*; 6 | 7 | use self::AxesVariant::*; 8 | use crate::axes2d::*; 9 | use crate::axes3d::*; 10 | 11 | use crate::options::{GnuplotVersion, MultiplotFillDirection, MultiplotFillOrder}; 12 | use crate::util::escape; 13 | use crate::writer::Writer; 14 | use std::fs::File; 15 | use std::io::{BufWriter, Write}; 16 | use std::path::{Path, PathBuf}; 17 | use std::process::{Child, Command, Stdio}; 18 | use std::str; 19 | use tempfile; 20 | 21 | enum AxesVariant 22 | { 23 | Axes2DType(Axes2D), 24 | Axes3DType(Axes3D), 25 | NewPage, 26 | } 27 | 28 | impl AxesVariant 29 | { 30 | fn write_out( 31 | &self, data_directory: Option<&str>, writer: &mut dyn Writer, auto_layout: bool, 32 | version: GnuplotVersion, 33 | ) 34 | { 35 | match *self 36 | { 37 | Axes2DType(ref a) => a.write_out(data_directory, writer, auto_layout, version), 38 | Axes3DType(ref a) => a.write_out(data_directory, writer, auto_layout, version), 39 | NewPage => 40 | { 41 | writeln!(writer, "unset multiplot"); 42 | writeln!(writer, "set multiplot"); 43 | } 44 | } 45 | } 46 | 47 | fn reset_state(&self, writer: &mut dyn Writer) 48 | { 49 | match *self 50 | { 51 | Axes2DType(ref a) => a.reset_state(writer), 52 | Axes3DType(ref a) => a.reset_state(writer), 53 | _ => (), 54 | } 55 | } 56 | } 57 | 58 | /// A struct that contains all the multiplot layout options 59 | struct MultiplotOptions 60 | { 61 | rows: usize, 62 | columns: usize, 63 | title: Option, 64 | scale_x: Option, 65 | scale_y: Option, 66 | offset_x: Option, 67 | offset_y: Option, 68 | fill_order: Option, 69 | fill_direction: Option, 70 | } 71 | 72 | impl MultiplotOptions 73 | { 74 | pub fn new() -> MultiplotOptions 75 | { 76 | MultiplotOptions { 77 | rows: 1, 78 | columns: 1, 79 | title: None, 80 | scale_x: None, 81 | scale_y: None, 82 | offset_x: None, 83 | offset_y: None, 84 | fill_order: None, 85 | fill_direction: None, 86 | } 87 | } 88 | } 89 | 90 | /// A sentinel that represents a gnuplot waiting to close. 91 | pub struct CloseSentinel 92 | { 93 | gnuplot: Child, 94 | } 95 | 96 | impl CloseSentinel 97 | { 98 | fn new(gnuplot: Child) -> Self 99 | { 100 | CloseSentinel { gnuplot } 101 | } 102 | 103 | /// Waits until the gnuplot process exits. See `std::process::Child::wait`. 104 | pub fn wait(&mut self) -> std::io::Result 105 | { 106 | self.gnuplot.wait() 107 | } 108 | 109 | /// Waits until the gnuplot process exits. See 110 | /// `std::process::Child::try_wait`. 111 | pub fn try_wait(&mut self) -> std::io::Result> 112 | { 113 | self.gnuplot.try_wait() 114 | } 115 | } 116 | 117 | impl Drop for CloseSentinel 118 | { 119 | fn drop(&mut self) 120 | { 121 | self.wait().unwrap(); 122 | } 123 | } 124 | 125 | /// A figure that may contain multiple axes. 126 | pub struct Figure 127 | { 128 | axes: Vec, 129 | terminal: String, 130 | enhanced_text: bool, 131 | output_file: Option, 132 | post_commands: String, 133 | pre_commands: String, 134 | // RefCell so that we can echo to it 135 | gnuplot: Option, 136 | version: Option, 137 | multiplot_options: Option, 138 | data_directory: Option, 139 | data_tempdir: Option, 140 | } 141 | 142 | impl Default for GnuplotVersion 143 | { 144 | fn default() -> GnuplotVersion 145 | { 146 | GnuplotVersion { major: 5, minor: 0 } 147 | } 148 | } 149 | 150 | impl Default for Figure 151 | { 152 | fn default() -> Self 153 | { 154 | Self::new() 155 | } 156 | } 157 | 158 | impl Figure 159 | { 160 | /// Creates a new figure. 161 | pub fn new() -> Figure 162 | { 163 | let data_tempdir = tempfile::tempdir().ok(); 164 | Figure { 165 | axes: Vec::new(), 166 | terminal: "".into(), 167 | enhanced_text: true, 168 | output_file: None, 169 | gnuplot: None, 170 | post_commands: "".into(), 171 | pre_commands: "".into(), 172 | version: None, 173 | multiplot_options: None, 174 | data_directory: data_tempdir 175 | .as_ref() 176 | .and_then(|d| d.path().to_str()) 177 | .map(|s| s.into()), 178 | data_tempdir: data_tempdir, 179 | } 180 | } 181 | 182 | /// Set the directory where to write the data. 183 | /// 184 | /// Gnuplot needs to reify the data before it can be plotted. By default, this is done by 185 | /// writing out data files into a temporary directory. This behavior can be restored by passing 186 | /// in `Some("".into())`. 187 | /// 188 | /// This can be set to `None`, in which case the data is written inline, without a temporary 189 | /// directory. Note that this has somewhat spotty support in gnuplot, so should probably be 190 | /// avoided. 191 | pub fn set_data_directory(&mut self, data_directory: Option) -> &mut Self 192 | { 193 | self.data_directory = data_directory; 194 | if self 195 | .data_directory 196 | .as_ref() 197 | .map(|s| s == "") 198 | .unwrap_or(false) 199 | { 200 | self.data_directory = self 201 | .data_tempdir 202 | .as_ref() 203 | .and_then(|d| d.path().to_str()) 204 | .map(|s| s.into()) 205 | } 206 | self 207 | } 208 | 209 | /// Sets the terminal for gnuplot to use, as well as the file to output the figure to. 210 | /// Terminals that spawn a GUI don't need an output file, so pass an empty string for those. 211 | /// 212 | /// There are a quite a number of terminals, here are some commonly used ones: 213 | /// 214 | /// * wxt - Interactive GUI 215 | /// * pdfcairo - Saves the figure as a PDF file 216 | /// * epscairo - Saves the figure as a EPS file 217 | /// * pngcairo - Saves the figure as a PNG file 218 | /// * svg - Saves the figure as a SVG file 219 | /// * canvas - Saves the figure as an HTML5 canvas element 220 | /// 221 | /// As of now you can hack the canvas size in by using "pngcairo size 600, 400" for `terminal`. 222 | /// Be prepared for that kludge to go away, though. 223 | pub fn set_terminal<'l>(&'l mut self, terminal: &str, output_file: &str) -> &'l mut Figure 224 | { 225 | self.terminal = terminal.into(); 226 | self.output_file = if output_file.is_empty() 227 | { 228 | None 229 | } 230 | else 231 | { 232 | Some(output_file.into()) 233 | }; 234 | self 235 | } 236 | 237 | /// Set or unset text enhancements 238 | pub fn set_enhanced_text(&mut self, enhanced: bool) -> &mut Figure 239 | { 240 | self.enhanced_text = enhanced; 241 | self 242 | } 243 | 244 | /// Sets commands to send to gnuplot after all the plotting commands. 245 | pub fn set_post_commands(&mut self, post_commands: &str) -> &mut Figure 246 | { 247 | self.post_commands = post_commands.into(); 248 | self 249 | } 250 | 251 | /// Sets commands to send to gnuplot before any plotting commands. 252 | pub fn set_pre_commands(&mut self, pre_commands: &str) -> &mut Figure 253 | { 254 | self.pre_commands = pre_commands.into(); 255 | self 256 | } 257 | 258 | /// Sets the Gnuplot version. 259 | /// 260 | /// By default, we assume version 5.0. If `show` is called, it will attempt 261 | /// to parse Gnuplot's version string as well. 262 | pub fn set_gnuplot_version(&mut self, version: Option) -> &mut Figure 263 | { 264 | self.version = version; 265 | self 266 | } 267 | 268 | /// Returns the Gnuplot version. 269 | pub fn get_gnuplot_version(&self) -> GnuplotVersion 270 | { 271 | self.version.unwrap_or_default() 272 | } 273 | 274 | /// Define the layout for the multiple plots 275 | /// # Arguments 276 | /// * `rows` - Number of rows 277 | /// * `columns` - Number of columns 278 | pub fn set_multiplot_layout(&mut self, rows: usize, columns: usize) -> &mut Self 279 | { 280 | let multiplot_options = self 281 | .multiplot_options 282 | .get_or_insert(MultiplotOptions::new()); 283 | multiplot_options.rows = rows; 284 | multiplot_options.columns = columns; 285 | 286 | self 287 | } 288 | 289 | /// Set the multiplot title 290 | /// # Arguments 291 | /// * `title` - Name of the file 292 | pub fn set_title(&mut self, title: &str) -> &mut Self 293 | { 294 | let multiplot_options = self 295 | .multiplot_options 296 | .get_or_insert(MultiplotOptions::new()); 297 | multiplot_options.title = Some(title.into()); 298 | 299 | self 300 | } 301 | 302 | /// Applies a horizontal and vertical scale to each plot 303 | /// # Arguments 304 | /// * `scale_x` - Horizonal scale applied to each plot 305 | /// * `scale_y` - Vertical scale applied to each plot 306 | pub fn set_scale(&mut self, scale_x: f32, scale_y: f32) -> &mut Self 307 | { 308 | let multiplot_options = self 309 | .multiplot_options 310 | .get_or_insert(MultiplotOptions::new()); 311 | multiplot_options.scale_x = Some(scale_x); 312 | multiplot_options.scale_y = Some(scale_y); 313 | 314 | self 315 | } 316 | 317 | /// Applies a horizontal and vertical offset to each plot 318 | /// # Arguments 319 | /// * `offset_x` - Horizontal offset applied to each plot 320 | /// * `offset_y` - Horizontal offset applied to each plot 321 | pub fn set_offset(&mut self, offset_x: f32, offset_y: f32) -> &mut Self 322 | { 323 | let multiplot_options = self 324 | .multiplot_options 325 | .get_or_insert(MultiplotOptions::new()); 326 | multiplot_options.offset_x = Some(offset_x); 327 | multiplot_options.offset_y = Some(offset_y); 328 | 329 | self 330 | } 331 | 332 | /// Defines the order in which plots fill the layout. Default is RowsFirst and Downwards. 333 | /// # Arguments 334 | /// * `order` - Options: RowsFirst, ColumnsFirst 335 | /// * `direction` - Options: Downwards, Upwards 336 | pub fn set_multiplot_fill_order( 337 | &mut self, order: MultiplotFillOrder, direction: MultiplotFillDirection, 338 | ) -> &mut Self 339 | { 340 | let multiplot_options = self 341 | .multiplot_options 342 | .get_or_insert(MultiplotOptions::new()); 343 | multiplot_options.fill_order = Some(order); 344 | multiplot_options.fill_direction = Some(direction); 345 | 346 | self 347 | } 348 | 349 | /// Creates a set of 2D axes 350 | pub fn axes2d(&mut self) -> &mut Axes2D 351 | { 352 | self.axes.push(Axes2DType(Axes2D::new())); 353 | let l = self.axes.len(); 354 | match self.axes[l - 1] 355 | { 356 | Axes2DType(ref mut a) => a, 357 | _ => unreachable!(), 358 | } 359 | } 360 | 361 | /// Creates a set of 3D axes 362 | pub fn axes3d(&mut self) -> &mut Axes3D 363 | { 364 | self.axes.push(Axes3DType(Axes3D::new())); 365 | let l = self.axes.len(); 366 | match self.axes[l - 1] 367 | { 368 | Axes3DType(ref mut a) => a, 369 | _ => unreachable!(), 370 | } 371 | } 372 | 373 | /// Creates a new page. 374 | /// 375 | /// Some terminals support multiple pages or frames, e.g. to create an 376 | /// animation. Call this function between sets of plots to indicate that a 377 | /// new page should be started. Note that this is implicit before any 378 | /// `axes2d`/`axes3d` calls, so make sure to call this only between pages 379 | /// (not once before every page). 380 | pub fn new_page(&mut self) -> &mut Figure 381 | { 382 | self.axes.push(NewPage); 383 | self 384 | } 385 | 386 | /// Launch a gnuplot process, if it hasn't been spawned already by a call to 387 | /// this function, and display the figure on it. 388 | /// 389 | /// Usually you should prefer using `show` instead. This method is primarily 390 | /// useful when you wish to call this multiple times, e.g. to redraw an 391 | /// existing plot window. 392 | pub fn show_and_keep_running(&mut self) -> Result<&mut Figure, GnuplotInitError> 393 | { 394 | if self.axes.is_empty() 395 | { 396 | return Ok(self); 397 | } 398 | 399 | if self.version.is_none() 400 | { 401 | let output = Command::new("gnuplot").arg("--version").output()?; 402 | 403 | if let Ok(version_string) = str::from_utf8(&output.stdout) 404 | { 405 | let parts: Vec<_> = version_string.split(|c| c == ' ' || c == '.').collect(); 406 | if parts.len() > 2 && parts[0] == "gnuplot" 407 | { 408 | if let (Ok(major), Ok(minor)) = 409 | (parts[1].parse::(), parts[2].parse::()) 410 | { 411 | self.version = Some(GnuplotVersion { major, minor }); 412 | } 413 | } 414 | } 415 | } 416 | 417 | if self.gnuplot.is_none() 418 | { 419 | self.gnuplot = Some( 420 | Command::new("gnuplot") 421 | .arg("-p") 422 | .stdin(Stdio::piped()) 423 | .spawn() 424 | .expect( 425 | "Couldn't spawn gnuplot. Make sure it is installed and available in PATH.", 426 | ), 427 | ); 428 | } 429 | 430 | { 431 | let mut gnuplot = self.gnuplot.take(); 432 | if let Some(p) = gnuplot.as_mut() 433 | { 434 | let stdin = p.stdin.as_mut().expect("No stdin!?"); 435 | self.echo(stdin); 436 | stdin.flush(); 437 | }; 438 | self.gnuplot = gnuplot; 439 | } 440 | 441 | Ok(self) 442 | } 443 | 444 | /// Launch a gnuplot process, if it hasn't been spawned already and 445 | /// display the figure on it. 446 | /// 447 | /// Unlike `show_and_keep_running`, this also instructs gnuplot to close if 448 | /// you close all of the plot windows. You can use the returned 449 | /// `CloseSentinel` to wait until this happens. 450 | pub fn show(&mut self) -> Result 451 | { 452 | self.show_and_keep_running()?; 453 | let mut gnuplot = self.gnuplot.take().expect("No gnuplot?"); 454 | { 455 | let stdin = gnuplot.stdin.as_mut().expect("No stdin!?"); 456 | writeln!(stdin, "pause mouse close"); 457 | writeln!(stdin, "quit"); 458 | }; 459 | Ok(CloseSentinel::new(gnuplot)) 460 | } 461 | 462 | /// Save the figure to a png file. 463 | /// 464 | /// # Arguments 465 | /// * `filename` - Path to the output file (png) 466 | /// * `width_px` - output image width (in pixels) 467 | /// * `height_px` - output image height (in pixels) 468 | pub fn save_to_png>( 469 | &mut self, filename: P, width_px: u32, height_px: u32, 470 | ) -> Result<(), GnuplotInitError> 471 | { 472 | let former_term = self.terminal.clone(); 473 | let former_output_file = self.output_file.clone(); 474 | self.terminal = format!("pngcairo size {},{}", width_px, height_px); 475 | self.output_file = Some(filename.as_ref().into()); 476 | self.show()?; 477 | self.terminal = former_term; 478 | self.output_file = former_output_file; 479 | 480 | Ok(()) 481 | } 482 | 483 | /// Save the figure to a svg file. 484 | /// 485 | /// # Arguments 486 | /// * `filename` - Path to the output file (svg) 487 | /// * `width_px` - output image width (in pixels) 488 | /// * `height_px` - output image height (in pixels) 489 | pub fn save_to_svg>( 490 | &mut self, filename: P, width_px: u32, height_px: u32, 491 | ) -> Result<(), GnuplotInitError> 492 | { 493 | let former_term = self.terminal.clone(); 494 | let former_output_file = self.output_file.clone(); 495 | self.terminal = format!("svg size {},{}", width_px, height_px); 496 | self.output_file = Some(filename.as_ref().into()); 497 | self.show()?; 498 | self.terminal = former_term; 499 | self.output_file = former_output_file; 500 | 501 | Ok(()) 502 | } 503 | 504 | /// Save the figure to a pdf file. 505 | /// 506 | /// # Arguments 507 | /// * `filename` - Path to the output file (pdf) 508 | /// * `width_in` - output image width (in inches) 509 | /// * `height_in` - output image height (in inches) 510 | pub fn save_to_pdf>( 511 | &mut self, filename: P, width_in: f32, height_in: f32, 512 | ) -> Result<(), GnuplotInitError> 513 | { 514 | let former_term = self.terminal.clone(); 515 | let former_output_file = self.output_file.clone(); 516 | self.terminal = format!("pdfcairo size {},{}", width_in, height_in); 517 | self.output_file = Some(filename.as_ref().into()); 518 | self.show()?; 519 | self.terminal = former_term; 520 | self.output_file = former_output_file; 521 | 522 | Ok(()) 523 | } 524 | 525 | /// Save the figure to an eps file 526 | /// 527 | /// # Arguments 528 | /// * `filename` - Path to the output file (eps) 529 | /// * `width_in` - output image width (in inches) 530 | /// * `height_in` - output image height (in inches) 531 | pub fn save_to_eps>( 532 | &mut self, filename: P, width_in: f32, height_in: f32, 533 | ) -> Result<(), GnuplotInitError> 534 | { 535 | let former_term = self.terminal.clone(); 536 | let former_output_file = self.output_file.clone(); 537 | self.terminal = format!("epscairo size {},{}", width_in, height_in); 538 | self.output_file = Some(filename.as_ref().into()); 539 | self.show()?; 540 | self.terminal = former_term; 541 | self.output_file = former_output_file; 542 | 543 | Ok(()) 544 | } 545 | 546 | /// Save the figure to a HTML5 canvas file 547 | /// 548 | /// # Arguments 549 | /// * `filename` - Path to the output file (canvas) 550 | /// * `width_px` - output image width (in pixels) 551 | /// * `height_px` - output image height (in pixels) 552 | pub fn save_to_canvas>( 553 | &mut self, filename: P, width_px: u32, height_px: u32, 554 | ) -> Result<(), GnuplotInitError> 555 | { 556 | let former_term = self.terminal.clone(); 557 | let former_output_file = self.output_file.clone(); 558 | self.terminal = format!("canvas size {},{}", width_px, height_px); 559 | self.output_file = Some(filename.as_ref().into()); 560 | self.show()?; 561 | self.terminal = former_term; 562 | self.output_file = former_output_file; 563 | 564 | Ok(()) 565 | } 566 | 567 | /// Closes the gnuplot process. 568 | /// 569 | /// This can be useful if you're your plot output is a file and you need to 570 | /// that it was written. 571 | pub fn close(&mut self) -> &mut Figure 572 | { 573 | if self.gnuplot.is_none() 574 | { 575 | return self; 576 | } 577 | 578 | { 579 | if let Some(p) = self.gnuplot.as_mut() 580 | { 581 | { 582 | let stdin = p.stdin.as_mut().expect("No stdin!?"); 583 | writeln!(stdin, "quit"); 584 | } 585 | p.wait(); 586 | }; 587 | self.gnuplot = None; 588 | } 589 | 590 | self 591 | } 592 | 593 | /// Clears all axes on this figure. 594 | pub fn clear_axes(&mut self) -> &mut Figure 595 | { 596 | self.axes.clear(); 597 | self 598 | } 599 | 600 | /// Echo the commands that if piped to a gnuplot process would display the figure 601 | /// # Arguments 602 | /// * `writer` - A function pointer that will be called multiple times with the command text and data 603 | pub fn echo(&self, writer: &mut T) -> &Figure 604 | { 605 | let w = writer as &mut dyn Writer; 606 | writeln!(w, "{}", &self.pre_commands); 607 | 608 | if self.axes.is_empty() 609 | { 610 | return self; 611 | } 612 | 613 | writeln!(w, "set encoding utf8"); 614 | if !self.terminal.is_empty() 615 | { 616 | writeln!(w, "set terminal {}", self.terminal); 617 | } 618 | 619 | if let Some(ref output_file) = self.output_file 620 | { 621 | writeln!( 622 | w, 623 | "set output \"{}\"", 624 | escape(output_file.to_str().unwrap()) 625 | ); 626 | } 627 | 628 | writeln!(w, "set termoption dashed"); 629 | writeln!( 630 | w, 631 | "set termoption {}", 632 | if self.enhanced_text 633 | { 634 | "enhanced" 635 | } 636 | else 637 | { 638 | "noenhanced" 639 | } 640 | ); 641 | 642 | if self.axes.len() > 1 || self.multiplot_options.is_some() 643 | { 644 | let mut multiplot_options_string = "".to_string(); 645 | if let Some(m) = &self.multiplot_options 646 | { 647 | let fill_order = match m.fill_order 648 | { 649 | None => "", 650 | Some(fo) => match fo 651 | { 652 | MultiplotFillOrder::RowsFirst => " rowsfirst", 653 | MultiplotFillOrder::ColumnsFirst => " columnsfirst", 654 | }, 655 | }; 656 | 657 | let fill_direction = match m.fill_direction 658 | { 659 | None => "", 660 | Some(fd) => match fd 661 | { 662 | MultiplotFillDirection::Downwards => " downwards", 663 | MultiplotFillDirection::Upwards => " upwards", 664 | }, 665 | }; 666 | 667 | let title = m 668 | .title 669 | .as_ref() 670 | .map_or("".to_string(), |t| format!(" title \"{}\"", escape(t))); 671 | let scale = m.scale_x.map_or("".to_string(), |s| { 672 | format!(" scale {},{}", s, m.scale_y.unwrap()) 673 | }); 674 | let offset = m.offset_x.map_or("".to_string(), |o| { 675 | format!(" offset {},{}", o, m.offset_y.unwrap()) 676 | }); 677 | 678 | multiplot_options_string = format!( 679 | " layout {},{}{}{}{}{}{}", 680 | m.rows, m.columns, fill_order, fill_direction, title, scale, offset 681 | ); 682 | } 683 | 684 | writeln!(w, "set multiplot{}", multiplot_options_string); 685 | } 686 | 687 | let mut prev_e: Option<&AxesVariant> = None; 688 | for (i, e) in self.axes.iter().enumerate() 689 | { 690 | if let Some(prev_e) = prev_e 691 | { 692 | prev_e.reset_state(w); 693 | } 694 | let out_path = self.data_directory.as_ref().and_then(|d| { 695 | Path::new(&d) 696 | .join(i.to_string()) 697 | .to_str() 698 | .map(|s| s.to_string()) 699 | }); 700 | if let Some(out_path) = out_path.as_ref() 701 | { 702 | std::fs::create_dir_all(out_path).ok(); 703 | } 704 | e.write_out( 705 | out_path.as_deref(), 706 | w, 707 | self.multiplot_options.is_some(), 708 | self.get_gnuplot_version(), 709 | ); 710 | prev_e = Some(e); 711 | } 712 | 713 | if self.axes.len() > 1 || self.multiplot_options.is_some() 714 | { 715 | writeln!(w, "unset multiplot"); 716 | } 717 | writeln!(w, "{}", &self.post_commands); 718 | self 719 | } 720 | 721 | /// Save to a file the the commands that if piped to a gnuplot process would display the figure 722 | /// # Arguments 723 | /// * `filename` - Name of the file 724 | pub fn echo_to_file>(&self, filename: P) -> &Figure 725 | { 726 | if self.axes.is_empty() 727 | { 728 | return self; 729 | } 730 | 731 | let mut file = BufWriter::new(File::create(filename).unwrap()); 732 | self.echo(&mut file); 733 | file.flush(); 734 | self 735 | } 736 | } 737 | 738 | impl Drop for Figure 739 | { 740 | fn drop(&mut self) 741 | { 742 | self.close(); 743 | } 744 | } 745 | 746 | #[test] 747 | fn flush_test() 748 | { 749 | use std::fs; 750 | use tempfile::TempDir; 751 | 752 | let tmp_path = TempDir::new().unwrap().into_path(); 753 | let filename = tmp_path.join("plot.png"); 754 | let mut fg = Figure::new(); 755 | fg.axes2d().boxes(0..5, 0..5, &[]); 756 | fg.set_terminal("pngcairo", &*filename.to_string_lossy()); 757 | fg.show(); 758 | fs::read(filename).unwrap(); 759 | fs::remove_dir_all(&tmp_path); 760 | } 761 | -------------------------------------------------------------------------------- /gnuplot/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2014 by SiegeLord 2 | // 3 | // All rights reserved. Distributed under LGPL 3.0. For full terms see the file LICENSE. 4 | 5 | #![allow(unused_must_use)] 6 | #![forbid(unstable_features)] 7 | /*! 8 | A simple gnuplot controller. 9 | 10 | # Example 11 | 12 | ~~~no_run 13 | # extern crate gnuplot; 14 | # fn main() { 15 | use gnuplot::{Figure, Caption, Color}; 16 | 17 | let x = [0u32, 1, 2]; 18 | let y = [3u32, 4, 5]; 19 | let mut fg = Figure::new(); 20 | fg.axes2d() 21 | .lines(&x, &y, &[Caption("A line"), Color("black".into())]); 22 | fg.show(); 23 | # } 24 | ~~~ 25 | */ 26 | pub use crate::axes2d::Axes2D; 27 | pub use crate::axes3d::Axes3D; 28 | pub use crate::axes_common::AxesCommon; 29 | pub use crate::color::*; 30 | pub use crate::coordinates::*; 31 | pub use crate::datatype::*; 32 | pub use crate::error_types::*; 33 | pub use crate::figure::*; 34 | pub use crate::options::*; 35 | 36 | #[macro_use] 37 | mod util; 38 | 39 | mod axes2d; 40 | mod axes3d; 41 | mod axes_common; 42 | mod color; 43 | mod coordinates; 44 | mod datatype; 45 | mod error_types; 46 | mod figure; 47 | mod options; 48 | pub mod palettes; 49 | mod writer; 50 | -------------------------------------------------------------------------------- /gnuplot/src/options.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2014 by SiegeLord 2 | // 3 | // All rights reserved. Distributed under LGPL 3.0. For full terms see the file LICENSE. 4 | 5 | pub use self::AlignType::*; 6 | pub use self::ArrowheadType::*; 7 | pub use self::AutoOption::*; 8 | pub use self::BorderLocation2D::*; 9 | pub use self::ContourStyle::*; 10 | pub use self::DashType::*; 11 | pub use self::FillPatternType::*; 12 | pub use self::FillRegionType::*; 13 | pub use self::LabelOption::*; 14 | pub use self::LegendOption::*; 15 | pub use self::MarginSide::*; 16 | pub use self::PaletteType::*; 17 | pub use self::PlotOption::*; 18 | pub use self::Tick::*; 19 | pub use self::TickOption::*; 20 | pub use self::XAxis::*; 21 | pub use self::YAxis::*; 22 | use crate::util::OneWayOwned; 23 | use crate::writer::Writer; 24 | use crate::ColorType; 25 | 26 | /// An enumeration of plot options you can supply to plotting commands, governing 27 | /// things like line width, color and others 28 | #[derive(Clone, Debug, PartialOrd, PartialEq)] 29 | pub enum PlotOption 30 | { 31 | /// Sets the symbol used for points. The valid characters are as follows: 32 | /// 33 | /// * `.` - dot 34 | /// * `+` - plus 35 | /// * `x` - cross 36 | /// * `*` - star 37 | /// * `s` - empty square 38 | /// * `S` - filled square 39 | /// * `o` - empty circle 40 | /// * `O` - filled circle 41 | /// * `t` - empty triangle 42 | /// * `T` - filled triangle 43 | /// * `d` - empty del (upside down triangle) 44 | /// * `D` - filled del (upside down triangle) 45 | /// * `r` - empty rhombus 46 | /// * `R` - filled rhombus 47 | PointSymbol(char), 48 | /// Sets the size of the points. The size acts as a multiplier, with 1.0 being the default. 49 | PointSize(f64), 50 | /// Sets the caption of the plot element. Set to empty to hide it from the legend. 51 | Caption(T), 52 | /// Sets the width of lines. 53 | LineWidth(f64), 54 | /// Sets the color of the plot element. The passed string can be a color name 55 | /// (e.g. "black" works), or an HTML color specifier (e.g. "#FFFFFF" is white). This specifies the fill color of a filled plot. 56 | Color(ColorType), 57 | /// Sets the color of the border of a filled plot (if it has one). The passed string can be a color name 58 | /// (e.g. "black" works), or an HTML color specifier (e.g. "#FFFFFF" is white). 59 | BorderColor(ColorType), 60 | /// Sets the style of the line. Note that not all gnuplot terminals support dashed lines. See DashType for the available styles. 61 | LineStyle(DashType), 62 | /// Sets the transparency of a filled plot. `0.0` - fully transparent, `1.0` - fully opaque. Cannot be used with `FillPattern`. 63 | FillAlpha(f64), 64 | /// Sets the fill region. See `FillRegionType` for the available regions. 65 | FillRegion(FillRegionType), 66 | /// Sets the fill pattern. If left at `Auto`, the pattern alternates automatically. Otherwise, see `FillPatternType` for 67 | /// the available patterns. Cannot be used with `FillAlpha`. 68 | FillPattern(AutoOption), 69 | /// Sets what an arrowhead looks like 70 | ArrowType(ArrowheadType), 71 | /// Sets the size of the arrowhead. This is specified in the units of graph (i.e. `1.0` would make the arrow as big as the graph). 72 | ArrowSize(f64), 73 | /// Width of the whisker bars (as a fraction of the box width) for box and whisker plots. 74 | WhiskerBars(f64), 75 | /// Which axis pair to use for the plot element. 76 | Axes(XAxis, YAxis), 77 | /// Box width set per box for box plots: each element is the width of one box 78 | BoxWidth(Vec), 79 | } 80 | 81 | impl<'l> OneWayOwned for PlotOption<&'l str> 82 | { 83 | type Output = PlotOption; 84 | fn to_one_way_owned(&self) -> Self::Output 85 | { 86 | match *self 87 | { 88 | PointSymbol(v) => PointSymbol(v), 89 | PointSize(v) => PointSize(v), 90 | Caption(v) => Caption(v.into()), 91 | LineWidth(v) => LineWidth(v), 92 | Color(ref v) => Color(v.to_one_way_owned()), 93 | BorderColor(ref v) => BorderColor(v.to_one_way_owned()), 94 | LineStyle(v) => LineStyle(v), 95 | FillAlpha(v) => FillAlpha(v), 96 | FillRegion(v) => FillRegion(v), 97 | ArrowType(v) => ArrowType(v), 98 | ArrowSize(v) => ArrowSize(v), 99 | WhiskerBars(v) => WhiskerBars(v), 100 | FillPattern(v) => FillPattern(v), 101 | Axes(x, y) => Axes(x, y), 102 | BoxWidth(ref d) => BoxWidth(d.clone()), 103 | } 104 | } 105 | } 106 | 107 | /// An enumeration of possible X-axes 108 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 109 | pub enum XAxis 110 | { 111 | X1, 112 | X2, 113 | } 114 | 115 | /// An enumeration of possible Y-axes 116 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 117 | pub enum YAxis 118 | { 119 | Y1, 120 | Y2, 121 | } 122 | 123 | /// An enumeration of possible fill regions 124 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 125 | pub enum FillRegionType 126 | { 127 | Above, 128 | Below, 129 | Between, 130 | } 131 | 132 | /// An enumeration of possible text and label alignments 133 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 134 | pub enum AlignType 135 | { 136 | AlignLeft, 137 | AlignRight, 138 | AlignCenter, 139 | AlignTop, 140 | AlignBottom, 141 | } 142 | 143 | /// An enumeration of possible dash styles 144 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 145 | pub enum DashType 146 | { 147 | Solid, 148 | SmallDot, 149 | Dot, 150 | Dash, 151 | DotDash, 152 | DotDotDash, 153 | } 154 | 155 | impl DashType 156 | { 157 | pub fn to_int(&self) -> i32 158 | { 159 | match *self 160 | { 161 | Solid => 1, 162 | SmallDot => 0, 163 | Dash => 2, 164 | Dot => 3, 165 | DotDash => 4, 166 | DotDotDash => 5, 167 | } 168 | } 169 | } 170 | 171 | /// An enumeration of possible arrow head styles 172 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 173 | pub enum ArrowheadType 174 | { 175 | /// An arrow head shaped like a 'V' 176 | Open, 177 | /// An arrow head shaped like an outlined triangle 178 | Closed, 179 | /// An arrow head shaped like a filled triangle 180 | Filled, 181 | /// No arrow head 182 | NoArrow, 183 | } 184 | 185 | /// An enumeration of something that can either be fixed (e.g. the maximum of X values), 186 | /// or automatically determined 187 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 188 | pub enum AutoOption 189 | { 190 | /// Fixes the value to a specific value 191 | Fix(T), 192 | /// Lets the value scale automatically 193 | Auto, 194 | } 195 | 196 | impl AutoOption 197 | { 198 | /// Same as `Option::map` 199 | pub fn map U>(self, f: F) -> AutoOption 200 | { 201 | match self 202 | { 203 | Fix(v) => Fix(f(v)), 204 | Auto => Auto, 205 | } 206 | } 207 | } 208 | 209 | impl OneWayOwned for AutoOption 210 | { 211 | type Output = AutoOption; 212 | fn to_one_way_owned(&self) -> Self::Output 213 | { 214 | match self 215 | { 216 | Fix(v) => Fix(v.to_string()), 217 | Auto => Auto, 218 | } 219 | } 220 | } 221 | 222 | /// An enumeration of label options that control label attributes 223 | #[derive(Clone, Debug, PartialOrd, PartialEq)] 224 | pub enum LabelOption 225 | { 226 | /// Sets the offset of the label in characters 227 | TextOffset(f64, f64), 228 | /// Sets the font of the label. The string specifies the font type (e.g. "Arial") and the number specifies the size (the units are terminal dependent, but are often points) 229 | Font(T, f64), 230 | /// Sets the color of the label text. The passed string can be a color name 231 | /// (e.g. "black" works), or an HTML color specifier (e.g. "#FFFFFF" is white) 232 | TextColor(ColorType), 233 | /// Rotates the label by a certain number of degrees 234 | Rotate(f64), 235 | /// Sets the horizontal alignment of the label text (default is left alignment). See AlignType. 236 | TextAlign(AlignType), 237 | /// Sets a marker for the label. By default no marker is drawn. The valid characters are as follows: 238 | /// 239 | /// * `.` - dot 240 | /// * `+` - plus 241 | /// * `x` - cross 242 | /// * `*` - star 243 | /// * `s` - empty square 244 | /// * `S` - filled square 245 | /// * `o` - empty circle 246 | /// * `O` - filled circle 247 | /// * `t` - empty triangle 248 | /// * `T` - filled triangle 249 | /// * `d` - empty del (upside down triangle) 250 | /// * `D` - filled del (upside down triangle) 251 | /// * `r` - empty rhombus 252 | /// * `R` - filled rhombus 253 | MarkerSymbol(char), 254 | /// Sets the color of the marker. The passed string can be a color name 255 | /// (e.g. "black" works), or an HTML color specifier (e.g. "#FFFFFF" is white) 256 | MarkerColor(ColorType), 257 | /// Sets the size of the marker. The size acts as a multiplier, with 1.0 being the default. 258 | MarkerSize(f64), 259 | } 260 | 261 | impl<'l> OneWayOwned for LabelOption<&'l str> 262 | { 263 | type Output = LabelOption; 264 | fn to_one_way_owned(&self) -> Self::Output 265 | { 266 | match self.clone() 267 | { 268 | TextOffset(v1, v2) => TextOffset(v1, v2), 269 | Font(v1, v2) => Font(v1.into(), v2), 270 | TextColor(v) => TextColor(v.to_one_way_owned()), 271 | Rotate(v) => Rotate(v), 272 | TextAlign(v) => TextAlign(v), 273 | MarkerSymbol(v) => MarkerSymbol(v), 274 | MarkerColor(v) => MarkerColor(v.to_one_way_owned()), 275 | MarkerSize(v) => MarkerSize(v), 276 | } 277 | } 278 | } 279 | 280 | /// An enumeration of axis tick options 281 | #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] 282 | pub enum TickOption 283 | { 284 | /// Specifies whether the ticks are drawn at the borders of the plot, or on the axis 285 | OnAxis(bool), 286 | /// If the axes are drawn on the border, this specifies whether to draw the ticks on the opposite border as well 287 | Mirror(bool), 288 | /// If the axes are drawn on the border, this specifies whether to draw the ticks pointing inward or outward 289 | Inward(bool), 290 | /// Sets the scale of the minor ticks 291 | MinorScale(f64), 292 | /// Sets the scale of the major ticks 293 | MajorScale(f64), 294 | /// Format of the tick labels, e.g. "%.1f ms" will produces labels with "1 ms, 2 ms" etc. 295 | Format(T), 296 | } 297 | 298 | impl<'l> OneWayOwned for TickOption<&'l str> 299 | { 300 | type Output = TickOption; 301 | fn to_one_way_owned(&self) -> Self::Output 302 | { 303 | match *self 304 | { 305 | OnAxis(v) => OnAxis(v), 306 | Mirror(v) => Mirror(v), 307 | Inward(v) => Inward(v), 308 | MinorScale(v) => MinorScale(v), 309 | MajorScale(v) => MajorScale(v), 310 | Format(v) => Format(v.into()), 311 | } 312 | } 313 | } 314 | 315 | /// Specifies a type of axis tick 316 | #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 317 | pub enum Tick 318 | { 319 | /// Major ticks have position and an optional label. The label may have a single C-style format specifier which will be replaced by the location of the tick 320 | Major(T, AutoOption), 321 | /// Minor ticks only have position 322 | Minor(T), 323 | } 324 | 325 | impl<'l, T: Clone, S: ToString> OneWayOwned for Tick 326 | { 327 | type Output = Tick; 328 | fn to_one_way_owned(&self) -> Self::Output 329 | { 330 | match self 331 | { 332 | Minor(v) => Minor(v.clone()), 333 | Major(v, s) => Major(v.clone(), s.to_one_way_owned()), 334 | } 335 | } 336 | } 337 | 338 | /// Plot border locations 339 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 340 | pub enum BorderLocation2D 341 | { 342 | Bottom = 1, 343 | Left = 2, 344 | Top = 4, 345 | Right = 8, 346 | } 347 | 348 | /// Plot margins 349 | #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] 350 | pub enum MarginSide 351 | { 352 | MarginLeft(f32), 353 | MarginRight(f32), 354 | MarginTop(f32), 355 | MarginBottom(f32), 356 | } 357 | 358 | /// Legend options 359 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 360 | pub enum LegendOption 361 | { 362 | /// Puts curve samples to the left of the label 363 | Reverse, 364 | /// Displays legend entries in opposite order 365 | Invert, 366 | /// Makes the legend horizontal (default is vertical) 367 | Horizontal, 368 | /// Specifies the location of the legend. The first argument specifies the horizontal 369 | /// placement with respect to its position, and the second argument specifies the vertical placement 370 | Placement(AlignType, AlignType), 371 | /// Title of the legend 372 | Title(T), 373 | /// Specifies the maximum number of rows, when the legend is vertical 374 | MaxRows(u32), 375 | /// Specifies the maximum number of columns, when the legend is horizontal 376 | MaxCols(u32), 377 | } 378 | 379 | impl<'l> OneWayOwned for LegendOption<&'l str> 380 | { 381 | type Output = LegendOption; 382 | fn to_one_way_owned(&self) -> Self::Output 383 | { 384 | match *self 385 | { 386 | Reverse => Reverse, 387 | Invert => Invert, 388 | Horizontal => Horizontal, 389 | Placement(v1, v2) => Placement(v1, v2), 390 | Title(v) => Title(v.into()), 391 | MaxRows(v) => MaxRows(v), 392 | MaxCols(v) => MaxCols(v), 393 | } 394 | } 395 | } 396 | 397 | /// Specifies how the contours are drawn 398 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 399 | pub enum ContourStyle 400 | { 401 | /// Draw lines between points of equal value 402 | Linear, 403 | /// Draw somewhat smoother curves between points with equal value. 404 | /// 405 | /// The argument specifies the number of points to use to approximate the 406 | /// curve for the final drawing step (clamped to range from 2 to 100). 407 | Cubic(u32), 408 | /// Draw an even smoother curve, this time approximating the locations of 409 | /// points with equal value (clamped to range from 2 to 100). 410 | /// 411 | /// The first argument specifies the number of points to use to approximate 412 | /// the curve for the final drawing step. The second argument specifies the 413 | /// order of the polynomial (clamped to range from 2 to 10). 414 | Spline(u32, u32), 415 | } 416 | 417 | /// Specifies what sort of palette to use 418 | #[derive(Clone, Debug, PartialOrd, PartialEq)] 419 | pub enum PaletteType 420 | { 421 | /// Use a gray palette with a specified gamma 422 | Gray(f32), 423 | /// Use a palette with that uses a predefined formula for each color component. 424 | /// Each formula is identified by an integer between [-36, 36]. See gnuplot documentation, or use the pre-defined constants. 425 | Formula(i32, i32, i32), 426 | /// Use a cube helix palette, with a certain start (in radians), cycles, saturation and gamma. 427 | CubeHelix(f32, f32, f32, f32), 428 | /// A custom palette 429 | /// is specified by a sequence of 4-tuples (with at least two elements). The first 430 | /// element is the grayscale value that is mapped to the remaining three elements 431 | /// which specify the red, green and blue components of the color. 432 | /// The grayscale values must be non-decreasing. All values must range from 0 to 1. 433 | Custom(T), 434 | } 435 | 436 | impl<'l> OneWayOwned for PaletteType<&'l [(f32, f32, f32, f32)]> 437 | { 438 | type Output = PaletteType>; 439 | fn to_one_way_owned(&self) -> Self::Output 440 | { 441 | match *self 442 | { 443 | Gray(v) => Gray(v), 444 | Formula(v1, v2, v3) => Formula(v1, v2, v3), 445 | CubeHelix(v1, v2, v3, v4) => CubeHelix(v1, v2, v3, v4), 446 | Custom(v) => Custom(v.into()), 447 | } 448 | } 449 | } 450 | 451 | /// A gray palette 452 | pub const GRAY: PaletteType<&'static [(f32, f32, f32, f32)]> = Gray(1.0); 453 | /// Default Gnuplot palette 454 | pub const COLOR: PaletteType<&'static [(f32, f32, f32, f32)]> = Formula(7, 5, 15); 455 | /// Classic rainbow palette with terrible perceptual properties 456 | pub const RAINBOW: PaletteType<&'static [(f32, f32, f32, f32)]> = Formula(33, 13, 10); 457 | /// A black body palette 458 | pub const HOT: PaletteType<&'static [(f32, f32, f32, f32)]> = Formula(34, 35, 36); 459 | /// A nice default for a cube helix 460 | pub const HELIX: PaletteType<&'static [(f32, f32, f32, f32)]> = CubeHelix(0.5, -0.8, 2.0, 1.0); 461 | 462 | impl PaletteType> 463 | { 464 | pub fn write_out_commands(&self, w: &mut dyn Writer) 465 | { 466 | match *self 467 | { 468 | Gray(gamma) => 469 | { 470 | assert!(gamma > 0.0, "Gamma must be positive"); 471 | writeln!(w, "set palette gray gamma {:.12e}", gamma); 472 | } 473 | Formula(r, g, b) => 474 | { 475 | assert!(r >= -36 && r <= 36, "Invalid r formula!"); 476 | assert!(g >= -36 && g <= 36, "Invalid g formula!"); 477 | assert!(b >= -36 && b <= 36, "Invalid b formula!"); 478 | writeln!(w, "set palette rgbformulae {},{},{}", r, g, b); 479 | } 480 | CubeHelix(start, rev, sat, gamma) => 481 | { 482 | assert!(sat >= 0.0, "Saturation must be non-negative"); 483 | assert!(gamma > 0.0, "Gamma must be positive"); 484 | writeln!( 485 | w, 486 | "set palette cubehelix start {:.12e} cycles {:.12e} saturation {:.12e} gamma {:.12e}", 487 | start, rev, sat, gamma 488 | ); 489 | } 490 | Custom(ref entries) => 491 | { 492 | if entries.len() < 2 493 | { 494 | panic!("Need at least 2 elements in a custom palette"); 495 | } 496 | write!(w, "set palette defined ("); 497 | 498 | let mut first = true; 499 | let mut old_x = 0.0; 500 | for &(x, r, g, b) in entries 501 | { 502 | if first 503 | { 504 | old_x = x; 505 | first = false; 506 | } 507 | else 508 | { 509 | write!(w, ","); 510 | } 511 | assert!(x >= old_x, "The gray levels must be non-decreasing!"); 512 | old_x = x; 513 | 514 | write!(w, "{:.12e} {:.12e} {:.12e} {:.12e}", x, r, g, b); 515 | } 516 | writeln!(w, ")"); 517 | } 518 | } 519 | } 520 | } 521 | 522 | /// Gnuplot version identifier. This is used to handle version-specific 523 | /// features. 524 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 525 | pub struct GnuplotVersion 526 | { 527 | pub major: i32, 528 | pub minor: i32, 529 | } 530 | 531 | /// Fill patterns. 532 | /// 533 | /// Note that these are not guaranteed to be consistent between terminals, 534 | /// but the following names appear to be the most common interpretations of 535 | /// the numerical values of these patterns. 536 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 537 | pub enum FillPatternType 538 | { 539 | Pattern0 = 0, 540 | BigCrosses = 1, 541 | SmallCrosses = 2, 542 | Pattern3 = 3, 543 | BigBackSlashes = 4, 544 | BigForwardSlashes = 5, 545 | SmallBackSlashes = 6, 546 | SmallForwardSlashes = 7, 547 | Pattern8 = 8, 548 | } 549 | 550 | /// Multiplot Fill Order Options 551 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 552 | pub enum MultiplotFillOrder 553 | { 554 | /// "rowsfirst" gnuplot option. 555 | RowsFirst, 556 | /// "columnfirst" gnuplot option. 557 | ColumnsFirst, 558 | } 559 | 560 | /// Multiplot Fill Order Options 561 | #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 562 | pub enum MultiplotFillDirection 563 | { 564 | /// "downward" gnuplot option. 565 | Downwards, 566 | /// "upward" gnuplot option. 567 | Upwards, 568 | } 569 | -------------------------------------------------------------------------------- /gnuplot/src/palettes/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2014 by SiegeLord 2 | // 3 | // All rights reserved. Distributed under LGPL 3.0. For full terms see the file LICENSE. 4 | 5 | mod cm_listed; 6 | 7 | pub use cm_listed::*; 8 | -------------------------------------------------------------------------------- /gnuplot/src/util.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2014 by SiegeLord 2 | // 3 | // All rights reserved. Distributed under LGPL 3.0. For full terms see the file LICENSE. 4 | 5 | macro_rules! first_opt 6 | { 7 | ($O: expr , $P: pat => $B: expr ) => 8 | ( 9 | for o in $O.iter() 10 | { 11 | match *o 12 | { 13 | $P => 14 | { 15 | $B 16 | break; 17 | }, 18 | _ => () 19 | }; 20 | } 21 | ) 22 | } 23 | 24 | macro_rules! first_opt_default 25 | { 26 | ($O: expr , $P: pat => $B: expr , _ => $E: expr ) => 27 | ( 28 | { 29 | let mut found = false; 30 | for o in $O.iter() 31 | { 32 | match *o 33 | { 34 | $P => 35 | { 36 | found = true; 37 | $B 38 | break; 39 | }, 40 | _ => () 41 | }; 42 | } 43 | if !found 44 | { 45 | $E 46 | } 47 | } 48 | ) 49 | } 50 | 51 | // returns (data, num_rows, num_cols) 52 | macro_rules! generate_data { 53 | ($options: ident, $( $d:ident ),*) => { 54 | { 55 | let mut widths = None; 56 | first_opt! {$options, 57 | BoxWidth(ref w) => 58 | { 59 | widths = Some(w); 60 | } 61 | } 62 | 63 | let mut c_data = None; 64 | first_opt! {$options, 65 | Color(ref color) => 66 | { 67 | if color.is_variable() { 68 | c_data = Some(color.data()); 69 | } 70 | } 71 | } 72 | 73 | if let Some(widths) = widths { 74 | if let Some(c_values) = c_data { 75 | generate_data_inner!( 76 | $( 77 | $d, 78 | )* 79 | widths, 80 | c_values 81 | ) 82 | } else { 83 | generate_data_inner!( 84 | $( 85 | $d, 86 | )* 87 | widths 88 | ) 89 | } 90 | } else { 91 | if let Some(c_values) = c_data { 92 | generate_data_inner!( 93 | $( 94 | $d, 95 | )* 96 | c_values 97 | ) 98 | } else { 99 | generate_data_inner!( 100 | $( 101 | $d, 102 | )* 103 | ) 104 | } 105 | } 106 | } 107 | } 108 | } 109 | 110 | // returns (data, num_rows, num_cols) 111 | macro_rules! generate_data_inner { 112 | ($( $d:ident ),* $(,)?) => { 113 | { 114 | let mut num_rows = 0; 115 | let num_cols = count_data!($($d )*); 116 | let mut data = vec![]; 117 | // TODO: Reserve. 118 | for nested_tuples!($($d,)*) in multizip!($($d, )*) //macro 119 | { 120 | $( data.push($d.get()); )* 121 | num_rows += 1; 122 | } 123 | (data, num_rows, num_cols) 124 | } 125 | } 126 | } 127 | 128 | macro_rules! nested_tuples { 129 | ($last: ident $(,)?)=> 130 | { 131 | $last 132 | }; 133 | ($first: ident, $( $tail:ident ),* $(,)? ) => { 134 | ($first, nested_tuples!($($tail, )*)) 135 | }; 136 | } 137 | 138 | macro_rules! multizip { 139 | ($last: ident $(,)?)=> 140 | { 141 | ($last.into_iter()) 142 | }; 143 | ($first: ident, $( $tail:ident ),* , ) => { 144 | $first.into_iter().zip(multizip!($($tail, )*)) 145 | }; 146 | } 147 | 148 | macro_rules! replace_expr { 149 | ($_t:tt $sub:expr) => { 150 | $sub 151 | }; 152 | } 153 | 154 | macro_rules! count_data { 155 | ($($data:tt)*) => {0usize $(+ replace_expr!($data 1usize))*}; 156 | } 157 | 158 | pub(crate) trait OneWayOwned 159 | { 160 | type Output; 161 | fn to_one_way_owned(&self) -> Self::Output; 162 | } 163 | 164 | impl<'l, T: OneWayOwned> OneWayOwned for &'l [T] 165 | { 166 | type Output = Vec<::Output>; 167 | fn to_one_way_owned(&self) -> Self::Output 168 | { 169 | self.iter().map(|v| v.to_one_way_owned()).collect() 170 | } 171 | } 172 | 173 | pub(crate) fn escape(s: &str) -> String 174 | { 175 | let mut res = String::with_capacity(s.len()); 176 | 177 | for c in s.chars() 178 | { 179 | match c 180 | { 181 | '\\' => res.push_str(r"\\"), 182 | '\n' => res.push_str(r"\n"), 183 | '\t' => res.push_str(r"\t"), 184 | '"' => res.push_str(r#"\""#), 185 | // gnuplot uses ` for command substitution, seems like a 186 | // terrible idea. 187 | '`' => res.push_str(r"\`"), 188 | c => res.push(c), 189 | } 190 | } 191 | res 192 | } 193 | 194 | #[test] 195 | fn escape_test() 196 | { 197 | assert_eq!(r"\\", escape(r"\")); 198 | assert_eq!(r"\\\\", escape(r"\\")); 199 | assert_eq!(r#"\\\""#, escape(r#"\""#)); 200 | assert_eq!(r#"\"\""#, escape(r#""""#)); 201 | assert_eq!(r"\n", escape("\n")); 202 | assert_eq!(r"\`", escape("`")); 203 | } 204 | -------------------------------------------------------------------------------- /gnuplot/src/writer.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013-2014 by SiegeLord 2 | // 3 | // All rights reserved. Distributed under LGPL 3.0. For full terms see the file LICENSE. 4 | 5 | use byteorder::{LittleEndian, WriteBytesExt}; 6 | use std::io::{self, Write}; 7 | 8 | pub trait Writer: Write 9 | { 10 | fn write_str(&mut self, s: &str) -> Result<(), io::Error> 11 | { 12 | self.write_all(s.as_bytes()) 13 | } 14 | 15 | fn write_le_f64(&mut self, v: f64) -> Result<(), io::Error> 16 | { 17 | self.write_f64::(v) 18 | } 19 | } 20 | 21 | impl Writer for T {} 22 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 100 2 | hard_tabs = true 3 | tab_spaces = 4 4 | newline_style = "Unix" 5 | use_small_heuristics = "Default" 6 | indent_style = "Block" 7 | wrap_comments = false 8 | format_code_in_doc_comments = false 9 | comment_width = 80 10 | normalize_comments = false 11 | normalize_doc_attributes = false 12 | format_strings = false 13 | format_macro_matchers = false 14 | format_macro_bodies = true 15 | empty_item_single_line = true 16 | struct_lit_single_line = true 17 | fn_single_line = false 18 | where_single_line = false 19 | imports_indent = "Block" 20 | imports_layout = "Mixed" 21 | imports_granularity="Preserve" 22 | reorder_imports = true 23 | reorder_modules = true 24 | reorder_impl_items = false 25 | type_punctuation_density = "Wide" 26 | space_before_colon = false 27 | space_after_colon = true 28 | spaces_around_ranges = false 29 | binop_separator = "Front" 30 | remove_nested_parens = true 31 | combine_control_expr = true 32 | overflow_delimited_expr = false 33 | struct_field_align_threshold = 0 34 | enum_discrim_align_threshold = 0 35 | match_arm_blocks = true 36 | force_multiline_blocks = false 37 | fn_params_layout = "Compressed" 38 | brace_style = "AlwaysNextLine" 39 | control_brace_style = "AlwaysNextLine" 40 | trailing_semicolon = true 41 | trailing_comma = "Vertical" 42 | match_block_trailing_comma = false 43 | blank_lines_upper_bound = 1 44 | blank_lines_lower_bound = 0 45 | edition = "2018" 46 | version = "One" 47 | inline_attribute_width = 0 48 | merge_derives = true 49 | use_try_shorthand = true 50 | condense_wildcard_suffixes = false 51 | force_explicit_abi = true 52 | use_field_init_shorthand = false 53 | color = "Auto" 54 | unstable_features = false 55 | disable_all_formatting = false 56 | skip_children = false 57 | hide_parse_errors = false 58 | error_on_line_overflow = false 59 | error_on_unformatted = false 60 | ignore = [] 61 | emit_mode = "Files" 62 | make_backup = false 63 | -------------------------------------------------------------------------------- /setup_venv.sh: -------------------------------------------------------------------------------- 1 | # This is meant to be sourced. 2 | 3 | uv venv venv 4 | . venv/bin/activate 5 | 6 | uv pip install pillow toml numpy 7 | --------------------------------------------------------------------------------