├── .github
└── workflows
│ └── CI.yml
├── .gitignore
├── LICENSE
├── README.md
├── codecov.yml
├── ford.md
├── fpm.toml
├── media
├── logo.png
└── logo.svg
├── pyplot-fortran.code-workspace
├── src
└── pyplot_module.F90
└── test
├── color_test.f90
├── date_test.f90
└── test.f90
/.github/workflows/CI.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on: [push]
3 | jobs:
4 |
5 | Build:
6 | runs-on: ${{ matrix.os }}
7 | permissions:
8 | contents: write
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | os: [ubuntu-latest]
13 | gcc_v: [10] # Version of GFortran we want to use.
14 | python-version: [3.9]
15 | env:
16 | FC: gfortran-${{ matrix.gcc_v }}
17 | GCC_V: ${{ matrix.gcc_v }}
18 |
19 | steps:
20 | - name: Checkout code
21 | uses: actions/checkout@v3
22 | with:
23 | submodules: recursive
24 |
25 | - name: Install Python
26 | uses: actions/setup-python@v4 # Use pip to install latest CMake, & FORD/Jin2For, etc.
27 | with:
28 | python-version: ${{ matrix.python-version }}
29 |
30 | - name: Setup Graphviz
31 | uses: ts-graphviz/setup-graphviz@v1
32 |
33 | - name: Setup Fortran Package Manager
34 | uses: fortran-lang/setup-fpm@v5
35 | with:
36 | github-token: ${{ secrets.GITHUB_TOKEN }}
37 |
38 | - name: Install Python dependencies
39 | if: contains( matrix.os, 'ubuntu')
40 | run: |
41 | python -m pip install --upgrade pip
42 | pip install numpy matplotlib ford
43 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
44 |
45 | - name: Install GFortran Linux
46 | if: contains( matrix.os, 'ubuntu')
47 | run: |
48 | sudo apt-get install lcov
49 | sudo add-apt-repository ppa:ubuntu-toolchain-r/test
50 | sudo apt-get update
51 | sudo apt-get install -y gcc-${{ matrix.gcc_v }} gfortran-${{ matrix.gcc_v }}
52 | sudo update-alternatives \
53 | --install /usr/bin/gcc gcc /usr/bin/gcc-${{ matrix.gcc_v }} 100 \
54 | --slave /usr/bin/gfortran gfortran /usr/bin/gfortran-${{ matrix.gcc_v }} \
55 | --slave /usr/bin/gcov gcov /usr/bin/gcov-${{ matrix.gcc_v }}
56 |
57 | # - name: Compile
58 | # run: fpm build --profile release
59 |
60 | - name: Run tests
61 | run: fpm test --profile release --flag -coverage
62 |
63 | - name: Create coverage report
64 | run: |
65 | mkdir -p ${{ env.COV_DIR }}
66 | mv ./build/gfortran_*/*/* ${{ env.COV_DIR }}
67 | lcov --capture --initial --base-directory . --directory ${{ env.COV_DIR }} --output-file ${{ env.COV_DIR }}/coverage.base
68 | lcov --capture --base-directory . --directory ${{ env.COV_DIR }} --output-file ${{ env.COV_DIR }}/coverage.capture
69 | lcov --add-tracefile ${{ env.COV_DIR }}/coverage.base --add-tracefile ${{ env.COV_DIR }}/coverage.capture --output-file ${{ env.COV_DIR }}/coverage.info
70 | env:
71 | COV_DIR: build/coverage
72 |
73 | - name: Upload coverage report
74 | uses: codecov/codecov-action@v3
75 | with:
76 | files: build/coverage/coverage.info
77 |
78 | - name: Build documentation
79 | run: ford ./ford.md
80 |
81 | - name: Deploy Documentation
82 | if: github.ref == 'refs/heads/master'
83 | uses: JamesIves/github-pages-deploy-action@v4.4.1
84 | with:
85 | branch: gh-pages # The branch the action should deploy to.
86 | folder: doc # The folder the action should deploy.
87 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | lib/
3 | doc/
4 | build/
5 | __pycache__
6 |
7 | # Compiled Object files
8 | *.slo
9 | *.lo
10 | *.o
11 | *.obj
12 |
13 | # Precompiled Headers
14 | *.gch
15 | *.pch
16 |
17 | # Compiled Dynamic libraries
18 | *.so
19 | *.dylib
20 | *.dll
21 |
22 | # Fortran module files
23 | *.mod
24 |
25 | # Compiled Static libraries
26 | *.lai
27 | *.la
28 | *.a
29 | *.lib
30 |
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 |
36 | # Generated Test Files
37 | test/*.png
38 | test/*.py
39 |
40 | # misc
41 | .DS_Store
42 | /env
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | PYPLOT-FORTRAN: For generating plots from Fortran using Python's matplotlib.pyplot.
2 |
3 | Copyright (c) 2015-2022, Jacob Williams
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice, this
13 | list of conditions and the following disclaimer in the documentation and/or
14 | other materials provided with the distribution.
15 |
16 | * The names of its contributors may not be used to endorse or promote products
17 | derived from this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | ============
3 |
4 | A simple module for generating plots from Fortran using Python's matplotlib.pyplot.
5 |
6 | ### Status
7 |
8 | [](https://github.com/jacobwilliams/pyplot-fortran/releases/latest)
9 | 
10 | [](https://codecov.io/gh/jacobwilliams/pyplot-fortran)
11 |
12 | ### Overview
13 |
14 | Currently, this module can be used to generate simple plots from Fortran. Eventually, it may be expanded to provide additional features and other types of plots.
15 |
16 | The way it works is simply to generate a Python script with the plotting code, which
17 | is then executed from the command line using the Fortran ```execute_command_line``` function.
18 |
19 | ### Compiling
20 |
21 | The module requires a modern Fortran compiler (it uses various Fortran 2003/2008 features such as deferred-length strings). It should work fine with the latest gfortran or ifort compilers.
22 |
23 | A `fpm.toml` file is provided for compiling pyplot-fortran with the [Fortran Package Manager](https://github.com/fortran-lang/fpm). For example, to build:
24 |
25 | ```
26 | fpm build --profile release
27 | ```
28 |
29 | By default, the library is built with double precision (`real64`) real values. Explicitly specifying the real kind can be done using the following processor flags:
30 |
31 | Preprocessor flag | Kind | Number of bytes
32 | ----------------- | ----- | ---------------
33 | `REAL32` | `real(kind=real32)` | 4
34 | `REAL64` | `real(kind=real64)` | 8
35 | `REAL128` | `real(kind=real128)` | 16
36 |
37 | For example, to build a single precision version of the library, use:
38 |
39 | ```
40 | fpm build --profile release --flag "-DREAL32"
41 | ```
42 |
43 | To run the unit tests:
44 |
45 | ```
46 | fpm test
47 | ```
48 |
49 | To use `pyplot-fortran` within your fpm project, add the following to your `fpm.toml` file:
50 | ```toml
51 | [dependencies]
52 | pyplot-fortran = { git="https://github.com/jacobwilliams/pyplot-fortran.git" }
53 | ```
54 |
55 | or, to use a specific version:
56 | ```toml
57 | [dependencies]
58 | pyplot-fortran = { git="https://github.com/jacobwilliams/pyplot-fortran.git", tag = "3.3.0" }
59 | ```
60 |
61 | To generate the documentation using [ford](https://github.com/Fortran-FOSS-Programmers/ford), run: ```ford ford.md```
62 |
63 | ### Supported plot types
64 |
65 | * `matplotlib.pyplot.plot` -- 2D/3D plot of lines and/or markers
66 | * `matplotlib.pyplot.bar` -- bar plot
67 | * `matplotlib.pyplot.contour` -- contour plot
68 | * `matplotlib.pyplot.contourf` -- filled contour plot
69 | * `matplotlib.pyplot.imshow` -- image plot
70 | * `matplotlib.pyplot.hist` -- histogram plot
71 | * `matplotlib.pyplot.errorbar` -- errorbar plot
72 | * `mpl_toolkits.mplot3d.axes3d.Axes3D.plot_surface` -- surface plot
73 | * `mpl_toolkits.mplot3d.axes3d.Axes3D.plot_wireframe` -- 3D wireframe
74 |
75 | ### Example
76 |
77 | The following example generates a plot of the sine function:
78 |
79 | ```fortran
80 | program test
81 |
82 | use,intrinsic :: iso_fortran_env, only: wp => real64
83 | use pyplot_module
84 |
85 | implicit none
86 |
87 | real(wp),dimension(100) :: x,sx
88 | type(pyplot) :: plt
89 | integer :: i
90 |
91 | !generate some data:
92 | x = [(real(i,wp), i=0,size(x)-1)]/5.0_wp
93 | sx = sin(x)
94 |
95 | !plot it:
96 | call plt%initialize(grid=.true.,xlabel='angle (rad)',&
97 | title='Plot of $\sin(x)$',legend=.true.)
98 | call plt%add_plot(x,sx,label='$\sin(x)$',linestyle='b-o',markersize=5,linewidth=2)
99 | call plt%savefig('sinx.png', pyfile='sinx.py')
100 |
101 | end program test
102 | ```
103 |
104 | ### Documentation
105 |
106 | * The API documentation for the current ```master``` branch can be found [here](https://jacobwilliams.github.io/pyplot-fortran/). This is generated by processing the source files with [FORD](https://github.com/Fortran-FOSS-Programmers/ford).
107 |
108 | ### See also
109 |
110 | * [Matplotlib](https://matplotlib.org)
111 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | comment:
2 | layout: header, changes, diff, sunburst
3 | coverage:
4 | ignore:
5 | - test
6 | - doc
7 | status:
8 | patch:
9 | default:
10 | target: 20%
11 | project:
12 | default:
13 | target: 70%
14 |
--------------------------------------------------------------------------------
/ford.md:
--------------------------------------------------------------------------------
1 | project: pyplot-fortran
2 | project_dir: src
3 | output_dir: doc
4 | media_dir: ./media
5 | project_github: https://github.com/jacobwilliams/pyplot-fortran
6 | summary: For generating plots from Fortran using Python's matplotlib.pyplot
7 | author: Jacob Williams
8 | github: https://github.com/jacobwilliams
9 | predocmark_alt: >
10 | predocmark: <
11 | docmark_alt:
12 | docmark: !
13 | display: public
14 | protected
15 | private
16 | source: true
17 | graph: true
18 |
19 | {!README.md!}
--------------------------------------------------------------------------------
/fpm.toml:
--------------------------------------------------------------------------------
1 | name = "pyplot-fortran"
2 | version = "3.1.0"
3 | author = "Jacob Williams"
4 | maintainer = "Jacob Williams"
5 | copyright = "Copyright (c) 2015-2022, Jacob Williams"
6 | license = "BSD-3"
7 | description = "A simple module for generating plots from Fortran using Python's matplotlib.pyplot."
8 | homepage = "https://github.com/jacobwilliams/pyplot-fortran"
9 |
10 | [library]
11 | source-dir = "src"
12 |
13 | [install]
14 | library = true
15 |
16 | [build]
17 | auto-executables = false
18 | auto-examples = false
19 | auto-tests = true
--------------------------------------------------------------------------------
/media/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacobwilliams/pyplot-fortran/60c5690c4e8d20d3185620db44111ca75ed7ebc3/media/logo.png
--------------------------------------------------------------------------------
/media/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
461 |
--------------------------------------------------------------------------------
/pyplot-fortran.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "."
5 | }
6 | ],
7 | "settings": {
8 | "files.trimTrailingWhitespace": true,
9 | "editor.insertSpaces": true,
10 | "editor.tabSize": 4,
11 | "editor.trimAutoWhitespace": true
12 | }
13 | }
--------------------------------------------------------------------------------
/src/pyplot_module.F90:
--------------------------------------------------------------------------------
1 | !*****************************************************************************************
2 | !> author: Jacob Williams
3 | ! date: 6/16/2017
4 | ! license: BSD
5 | !
6 | ! For making simple x-y plots from Fortran.
7 | ! It works by generating a Python script and executing it.
8 | !
9 | !# See also
10 | ! * Inspired by: [EasyPlot](https://pypi.python.org/pypi/EasyPlot)
11 | !
12 | !@note The default real kind (`wp`) can be
13 | ! changed using optional preprocessor flags.
14 | ! This library was built with real kind:
15 | #ifdef REAL32
16 | ! `real(kind=real32)` [4 bytes]
17 | #elif REAL64
18 | ! `real(kind=real64)` [8 bytes]
19 | #elif REAL128
20 | ! `real(kind=real128)` [16 bytes]
21 | #else
22 | ! `real(kind=real64)` [8 bytes]
23 | #endif
24 |
25 | module pyplot_module
26 |
27 | use, intrinsic :: iso_fortran_env
28 |
29 | implicit none
30 |
31 | private
32 |
33 | #ifdef REAL32
34 | integer,parameter,public :: pyplot_wp = real32 !! real kind used by this module [4 bytes]
35 | #elif REAL64
36 | integer,parameter,public :: pyplot_wp = real64 !! real kind used by this module [8 bytes]
37 | #elif REAL128
38 | integer,parameter,public :: pyplot_wp = real128 !! real kind used by this module [16 bytes]
39 | #else
40 | integer,parameter,public :: pyplot_wp = real64 !! real kind used by this module [8 bytes]
41 | #endif
42 |
43 | integer,parameter :: wp = pyplot_wp !! local copy of `pyplot_wp` with a shorter name
44 |
45 | character(len=*), parameter :: tmp_file = 'pyplot_module_temp_1234567890.py' !! Default name of the temporary file
46 | !! (this can also be user-specified).
47 |
48 | character(len=*), parameter :: python_exe ='python' !! The python executable name.
49 | character(len=*), parameter :: int_fmt = '(I10)' !! integer format string
50 | integer, parameter :: max_int_len = 10 !! max string length for integers
51 | character(len=*), parameter :: real_fmt_default = '(E30.16)' !! default real number format string
52 | integer, parameter :: max_real_len = 60 !! max string length for reals
53 |
54 | type, public :: pyplot
55 |
56 | !! The main pyplot class.
57 |
58 | private
59 |
60 | character(len=:), allocatable :: str !! string buffer
61 |
62 | character(len=1) :: raw_str_token = ' ' !! will be 'r' if using raw strings
63 |
64 | logical :: show_legend = .false. !! show legend into plot
65 | logical :: use_numpy = .true. !! use numpy python module
66 | logical :: use_oo_api = .false. !! use OO interface of matplotlib (incopatible with showfig subroutine)
67 | logical :: mplot3d = .false. !! it is a 3d plot
68 | logical :: polar = .false. !! it is a polar plot
69 | logical :: axis_equal = .false. !! equal scale on each axis
70 | logical :: axisbelow = .true. !! axis below other chart elements
71 | logical :: tight_layout = .false. !! tight layout option
72 | logical :: usetex = .false. !! enable LaTeX
73 |
74 | character(len=:),allocatable :: xaxis_date_fmt !! date format for the x-axis. Example: `"%m/%d/%y %H:%M:%S"`
75 | character(len=:),allocatable :: yaxis_date_fmt !! date format for the y-axis. Example: `"%m/%d/%y %H:%M:%S"`
76 |
77 | character(len=:),allocatable :: real_fmt !! real number formatting
78 |
79 | contains
80 |
81 | ! public methods
82 | procedure, public :: initialize !! initialize pyplot instance
83 |
84 | procedure, public :: add_plot !! add a 2d plot to pyplot instance
85 | procedure, public :: add_errorbar !! add a 2d error bar plot to pyplot instance
86 | procedure, public :: add_3d_plot !! add a 3d plot to pyplot instance
87 | procedure, public :: add_sphere !! add a 3d sphere to pyplot instance
88 | procedure, public :: add_contour !! add a contour plot to pyplot instance
89 | procedure, public :: plot_wireframe!! add a wireframe plot to pyplot instance
90 | procedure, public :: plot_surface !! add a surface plot to pyplot instance
91 | procedure, public :: add_bar !! add a barplot to pyplot instance
92 | procedure, public :: add_imshow !! add an image plot (using `imshow`)
93 | procedure, public :: add_hist !! add a histogram plot to pyplot instance
94 | procedure, public :: savefig !! save plots of pyplot instance
95 | procedure, public :: showfig !! show plots of pyplot instance
96 | procedure, public :: destroy !! destroy pyplot instance
97 |
98 | ! private methods
99 | procedure :: execute !! execute pyplot commands
100 | procedure :: add_str !! add string to pytplot instance buffer
101 | procedure :: finish_ops !! some final ops before saving
102 |
103 | end type pyplot
104 |
105 | contains
106 | !*****************************************************************************************
107 |
108 | !*****************************************************************************************
109 | !> author: Jacob Williams
110 | !
111 | ! Destructor.
112 |
113 | subroutine destroy(me)
114 |
115 | class(pyplot),intent(inout) :: me !! pyplot handler
116 |
117 | if (allocated(me%str)) deallocate(me%str)
118 | if (allocated(me%real_fmt)) deallocate(me%real_fmt)
119 |
120 | me%raw_str_token = ' '
121 |
122 | end subroutine destroy
123 | !*****************************************************************************************
124 |
125 | !*****************************************************************************************
126 | !> author: Jacob Williams
127 | !
128 | ! Add a string to the buffer.
129 |
130 | subroutine add_str(me,str)
131 |
132 | class(pyplot), intent(inout) :: me !! pyplot handler
133 | character(len=*), intent(in) :: str !! str to be added to pyplot handler buffer
134 |
135 | integer :: n_old !! current `me%str` length
136 | integer :: n_str !! length of input `str`
137 | character(len=:),allocatable :: tmp !! tmp string for building the result
138 |
139 | ! original
140 | !me%str = me%str//str//new_line(' ')
141 |
142 | if (len(str)==0) return
143 |
144 | ! the above can sometimes cause a stack overflow in the
145 | ! intel Fortran compiler, so we replace with this:
146 | if (allocated(me%str)) then
147 | n_old = len(me%str)
148 | n_str = len(str)
149 | allocate(character(len=n_old+n_str+1) :: tmp)
150 | tmp(1:n_old) = me%str
151 | tmp(n_old+1:) = str//new_line(' ')
152 | call move_alloc(tmp, me%str)
153 | else
154 | allocate(me%str, source = str//new_line(' '))
155 | end if
156 |
157 | end subroutine add_str
158 | !*****************************************************************************************
159 |
160 | !*****************************************************************************************
161 | !> author: Jacob Williams
162 | !
163 | ! Initialize a plot
164 |
165 | subroutine initialize(me, grid, xlabel, ylabel, zlabel, title, legend, use_numpy, figsize, &
166 | font_size, axes_labelsize, xtick_labelsize, ytick_labelsize, ztick_labelsize, &
167 | legend_fontsize, mplot3d, axis_equal, polar, real_fmt, use_oo_api, axisbelow,&
168 | tight_layout, raw_strings, usetex, xaxis_date_fmt, yaxis_date_fmt)
169 |
170 | class(pyplot), intent(inout) :: me !! pyplot handler
171 | logical, intent(in), optional :: grid !! activate grid drawing
172 | character(len=*), intent(in), optional :: xlabel !! label of x axis
173 | character(len=*), intent(in), optional :: ylabel !! label of y axis
174 | character(len=*), intent(in), optional :: zlabel !! label of z axis
175 | character(len=*), intent(in), optional :: title !! plot title
176 | logical, intent(in), optional :: legend !! plot legend
177 | logical, intent(in), optional :: use_numpy !! activate usage of numpy python module
178 | integer, dimension(2), intent(in), optional :: figsize !! dimension of the figure
179 | integer, intent(in), optional :: font_size !! font size
180 | integer, intent(in), optional :: axes_labelsize !! size of axis labels
181 | integer, intent(in), optional :: xtick_labelsize !! size of x axis tick lables
182 | integer, intent(in), optional :: ytick_labelsize !! size of y axis tick lables
183 | integer, intent(in), optional :: ztick_labelsize !! size of z axis tick lables
184 | integer, intent(in), optional :: legend_fontsize !! size of legend font
185 | logical, intent(in), optional :: mplot3d !! set true for 3d plots (cannot use with polar)
186 | logical, intent(in), optional :: axis_equal !! set true for axis = 'equal'
187 | logical, intent(in), optional :: polar !! set true for polar plots (cannot use with mplot3d)
188 | character(len=*), intent(in), optional :: real_fmt !! format string for real numbers (examples: '(E30.16)' [default], '*')
189 | logical, intent(in), optional :: use_oo_api !! avoid matplotlib's GUI by using the OO interface (cannot use with showfig)
190 | logical, intent(in), optional :: axisbelow !! to put the grid lines below the other chart elements [default is true]
191 | logical, intent(in), optional :: tight_layout !! enable tight layout [default is false]
192 | logical, intent(in), optional :: raw_strings !! if True, all strings sent to Python are treated as
193 | !! raw strings (e.g., r'str'). Default is False.
194 | logical, intent(in), optional :: usetex !! if True, enable LaTeX. (default if false)
195 | character(len=*), intent(in), optional :: xaxis_date_fmt !! if present, used to set the date format for the x-axis
196 | character(len=*), intent(in), optional :: yaxis_date_fmt !! if present, used to set the date format for the y-axis
197 |
198 | character(len=max_int_len) :: width_str !! figure width dummy string
199 | character(len=max_int_len) :: height_str !! figure height dummy string
200 | character(len=max_int_len) :: font_size_str !! font size dummy string
201 | character(len=max_int_len) :: axes_labelsize_str !! size of axis labels dummy string
202 | character(len=max_int_len) :: xtick_labelsize_str !! size of x axis tick labels dummy string
203 | character(len=max_int_len) :: ytick_labelsize_str !! size of x axis tick labels dummy string
204 | character(len=max_int_len) :: ztick_labelsize_str !! size of z axis tick labels dummy string
205 | character(len=max_int_len) :: legend_fontsize_str !! size of legend font dummy string
206 | character(len=:),allocatable :: python_fig_func !! Python's function for creating a new Figure instance
207 |
208 | character(len=*), parameter :: default_font_size_str = '10' !! the default font size for plots
209 |
210 | call me%destroy()
211 |
212 | if (present(raw_strings)) then
213 | if (raw_strings) me%raw_str_token = 'r'
214 | end if
215 |
216 | if (present(legend)) then
217 | me%show_legend = legend
218 | else
219 | me%show_legend = .false.
220 | end if
221 | if (present(use_numpy)) then
222 | me%use_numpy = use_numpy
223 | else
224 | me%use_numpy = .true.
225 | end if
226 | if (present(use_oo_api)) then
227 | me%use_oo_api = use_oo_api
228 | else
229 | me%use_oo_api = .false.
230 | end if
231 | if (present(figsize)) then
232 | call integer_to_string(figsize(1), width_str)
233 | call integer_to_string(figsize(2), height_str)
234 | end if
235 | if (present(mplot3d)) then
236 | me%mplot3d = mplot3d
237 | else
238 | me%mplot3d = .false.
239 | end if
240 | if (present(polar)) then
241 | me%polar = polar
242 | else
243 | me%polar = .false.
244 | end if
245 | if (present(axis_equal)) then
246 | me%axis_equal = axis_equal
247 | else
248 | me%axis_equal = .false.
249 | end if
250 | if (present(real_fmt)) then
251 | me%real_fmt = trim(adjustl(real_fmt))
252 | else
253 | me%real_fmt = real_fmt_default
254 | end if
255 | if (present(tight_layout)) then
256 | me%tight_layout = tight_layout
257 | else
258 | me%tight_layout = .false.
259 | end if
260 | if (present(usetex)) then
261 | me%usetex = usetex
262 | else
263 | me%usetex = .false.
264 | end if
265 | if (present(xaxis_date_fmt)) then
266 | me%xaxis_date_fmt = xaxis_date_fmt
267 | else
268 | if (allocated(me%xaxis_date_fmt)) deallocate(me%xaxis_date_fmt)
269 | end if
270 | if (present(yaxis_date_fmt)) then
271 | me%yaxis_date_fmt = yaxis_date_fmt
272 | else
273 | if (allocated(me%yaxis_date_fmt)) deallocate(me%yaxis_date_fmt)
274 | end if
275 |
276 | call optional_int_to_string(font_size, font_size_str, default_font_size_str)
277 | call optional_int_to_string(axes_labelsize, axes_labelsize_str, default_font_size_str)
278 | call optional_int_to_string(xtick_labelsize, xtick_labelsize_str, default_font_size_str)
279 | call optional_int_to_string(ytick_labelsize, ytick_labelsize_str, default_font_size_str)
280 | call optional_int_to_string(ztick_labelsize, ztick_labelsize_str, default_font_size_str)
281 | call optional_int_to_string(legend_fontsize, legend_fontsize_str, default_font_size_str)
282 |
283 | me%str = ''
284 |
285 | call me%add_str('#!/usr/bin/env python')
286 | call me%add_str('')
287 |
288 | call me%add_str('import matplotlib')
289 | if (me%use_oo_api) then
290 | call me%add_str('from matplotlib.figure import Figure')
291 | call me%add_str('from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas')
292 | else
293 | call me%add_str('import matplotlib.pyplot as plt')
294 | endif
295 | if (me%mplot3d) call me%add_str('from mpl_toolkits.mplot3d import Axes3D')
296 | if (me%use_numpy) call me%add_str('import numpy as np')
297 | call me%add_str('')
298 |
299 | call me%add_str('matplotlib.rcParams["font.family"] = "Serif"')
300 | call me%add_str('matplotlib.rcParams["font.size"] = '//trim(font_size_str))
301 | call me%add_str('matplotlib.rcParams["axes.labelsize"] = '//trim(axes_labelsize_str))
302 | call me%add_str('matplotlib.rcParams["xtick.labelsize"] = '//trim(xtick_labelsize_str))
303 | call me%add_str('matplotlib.rcParams["ytick.labelsize"] = '//trim(ytick_labelsize_str))
304 | call me%add_str('matplotlib.rcParams["legend.fontsize"] = '//trim(legend_fontsize_str))
305 | if (me%usetex) call me%add_str('matplotlib.rcParams["text.usetex"] = True')
306 |
307 | call me%add_str('')
308 |
309 | if (me%use_oo_api) then
310 | python_fig_func = 'Figure'
311 | else
312 | python_fig_func = 'plt.figure'
313 | endif
314 | if (present(figsize)) then !if specifying the figure size
315 | call me%add_str('fig = '//python_fig_func//'(figsize=('//trim(width_str)//','//trim(height_str)//'),facecolor="white")')
316 | else
317 | call me%add_str('fig = '//python_fig_func//'(facecolor="white")')
318 | end if
319 |
320 | if (me%mplot3d) then
321 | call me%add_str('ax = fig.add_subplot(1, 1, 1, projection=''3d'')')
322 | elseif (me%polar) then
323 | call me%add_str('ax = fig.add_subplot(1, 1, 1, projection=''polar'')')
324 | else
325 | call me%add_str('ax = fig.add_subplot(1, 1, 1)')
326 | end if
327 |
328 | if (present(grid)) then
329 | if (grid) call me%add_str('ax.grid()')
330 | end if
331 |
332 | if (present(axisbelow)) then
333 | me%axisbelow = axisbelow
334 | else
335 | me%axisbelow = .true. ! default
336 | end if
337 | if (me%axisbelow) call me%add_str('ax.set_axisbelow(True)')
338 |
339 | if (present(xlabel)) call me%add_str('ax.set_xlabel('//trim(me%raw_str_token)//'"'//trim(xlabel)//'")')
340 | if (present(ylabel)) call me%add_str('ax.set_ylabel('//trim(me%raw_str_token)//'"'//trim(ylabel)//'")')
341 | if (present(zlabel)) call me%add_str('ax.set_zlabel('//trim(me%raw_str_token)//'"'//trim(zlabel)//'")')
342 | if (present(title)) call me%add_str('ax.set_title('//trim(me%raw_str_token)//'"' //trim(title) //'")')
343 |
344 | call me%add_str('')
345 |
346 | end subroutine initialize
347 | !*****************************************************************************************
348 |
349 | !*****************************************************************************************
350 | !> author: Jacob Williams
351 | !
352 | ! Add an x,y plot.
353 |
354 | subroutine add_plot(me, x, y, label, linestyle, markersize, linewidth, xlim, ylim, xscale, yscale, color, istat)
355 |
356 | class(pyplot), intent (inout) :: me !! pyplot handler
357 | real(wp), dimension(:), intent (in) :: x !! x values
358 | real(wp), dimension(:), intent (in) :: y !! y values
359 | character(len=*), intent (in) :: label !! plot label
360 | character(len=*), intent (in) :: linestyle !! style of the plot line
361 | integer, intent (in), optional :: markersize !! size of the plot markers
362 | integer, intent (in), optional :: linewidth !! width of the plot line
363 | real(wp),dimension(2), intent (in), optional :: xlim !! x-axis range
364 | real(wp),dimension(2), intent (in), optional :: ylim !! y-axis range
365 | character(len=*), intent (in), optional :: xscale !! example: 'linear' (default), 'log'
366 | character(len=*), intent (in), optional :: yscale !! example: 'linear' (default), 'log'
367 | real(wp),dimension(:), intent (in), optional :: color !! RGB color tuple [0-1,0-1,0-1]
368 | integer, intent (out), optional :: istat !! status output (0 means no problems)
369 |
370 | character(len=:), allocatable :: arg_str !! the arguments to pass to `plot`
371 | character(len=:), allocatable :: xstr !! x values stringified
372 | character(len=:), allocatable :: ystr !! y values stringified
373 | character(len=:), allocatable :: xlimstr !! xlim values stringified
374 | character(len=:), allocatable :: ylimstr !! ylim values stringified
375 | character(len=:), allocatable :: color_str !! color values stringified
376 | character(len=max_int_len) :: imark !! actual markers size
377 | character(len=max_int_len) :: iline !! actual line width
378 | character(len=*), parameter :: xname = 'x' !! x variable name for script
379 | character(len=*), parameter :: yname = 'y' !! y variable name for script
380 |
381 | if (allocated(me%str)) then
382 |
383 | if (present(istat)) istat = 0
384 |
385 | !axis limits (optional):
386 | if (present(xlim)) call vec_to_string(xlim, me%real_fmt, xlimstr, me%use_numpy)
387 | if (present(ylim)) call vec_to_string(ylim, me%real_fmt, ylimstr, me%use_numpy)
388 |
389 | !convert the arrays to strings:
390 | call vec_to_string(x, me%real_fmt, xstr, me%use_numpy)
391 | call vec_to_string(y, me%real_fmt, ystr, me%use_numpy)
392 |
393 | !get optional inputs (if not present, set default value):
394 | call optional_int_to_string(markersize, imark, '3')
395 | call optional_int_to_string(linewidth, iline, '3')
396 |
397 | !write the arrays:
398 | call me%add_str(trim(xname)//' = '//xstr)
399 | call me%add_str(trim(yname)//' = '//ystr)
400 | call me%add_str('')
401 |
402 | !main arguments for plot:
403 | arg_str = trim(xname)//','//&
404 | trim(yname)//','//&
405 | trim(me%raw_str_token)//'"'//trim(linestyle)//'",'//&
406 | 'linewidth='//trim(adjustl(iline))//','//&
407 | 'markersize='//trim(adjustl(imark))//','//&
408 | 'label='//trim(me%raw_str_token)//'"'//trim(label)//'"'
409 |
410 | ! optional arguments:
411 | if (present(color)) then
412 | if (size(color)<=3) then
413 | call vec_to_string(color(1:3), '*', color_str, use_numpy=.false., is_tuple=.true.)
414 | arg_str = arg_str//',color='//trim(color_str)
415 | end if
416 | end if
417 |
418 | !write the plot statement:
419 | call me%add_str('ax.plot('//arg_str//')')
420 |
421 | !axis limits:
422 | if (allocated(xlimstr)) call me%add_str('ax.set_xlim('//xlimstr//')')
423 | if (allocated(ylimstr)) call me%add_str('ax.set_ylim('//ylimstr//')')
424 |
425 | !axis scales:
426 | if (present(xscale)) call me%add_str('ax.set_xscale('//trim(me%raw_str_token)//'"'//xscale//'")')
427 | if (present(yscale)) call me%add_str('ax.set_yscale('//trim(me%raw_str_token)//'"'//yscale//'")')
428 |
429 | call me%add_str('')
430 |
431 | else
432 | if (present(istat)) istat = -1
433 | write(error_unit,'(A)') 'Error in add_plot: pyplot class not properly initialized.'
434 | end if
435 |
436 | end subroutine add_plot
437 | !*****************************************************************************************
438 |
439 | !*****************************************************************************************
440 | !> author: Jimmy Leta
441 | !
442 | ! Add a histogram plot.
443 |
444 | subroutine add_hist(me, x, label, xlim, ylim, xscale, yscale, bins, normed, cumulative, istat)
445 |
446 | class(pyplot), intent (inout) :: me !! pyplot handler
447 | real(wp), dimension(:), intent (in) :: x !! array of data
448 | character(len=*), intent (in) :: label !! plot label
449 | real(wp),dimension(2), intent (in), optional :: xlim !! x-axis range
450 | real(wp),dimension(2), intent (in), optional :: ylim !! y-axis range
451 | character(len=*), intent (in), optional :: xscale !! example: 'linear' (default), 'log'
452 | character(len=*), intent (in), optional :: yscale !! example: 'linear' (default), 'log'
453 | integer, intent (in), optional :: bins !! number of bins
454 | logical, intent (in), optional :: normed !! boolean flag that determines whether bin counts are normalized [NO LONGER USED]
455 | logical, intent (in), optional :: cumulative !! boolean flag that determines whether histogram represents the cumulative density of dataset
456 | integer, intent (out),optional :: istat !! status output (0 means no problems)
457 |
458 | character(len=*), parameter :: xname = 'x' !! x variable name for script
459 | character(len=:), allocatable :: xstr !! x values stringified
460 | character(len=:), allocatable :: xlimstr !! xlim values stringified
461 | character(len=:), allocatable :: ylimstr !! ylim values stringified
462 | character(len=:), allocatable :: cumulativestr !!
463 | character(len=max_int_len) :: binsstr !!
464 |
465 | if (allocated(me%str)) then
466 |
467 | if (present(istat)) istat = 0
468 |
469 | !axis limits (optional):
470 | if (present(xlim)) call vec_to_string(xlim, me%real_fmt, xlimstr, me%use_numpy)
471 | if (present(ylim)) call vec_to_string(ylim, me%real_fmt, ylimstr, me%use_numpy)
472 |
473 | !convert the arrays to strings:
474 | call vec_to_string(x, me%real_fmt, xstr, me%use_numpy)
475 |
476 | !write the arrays:
477 | call me%add_str(trim(xname)//' = '//xstr)
478 | call me%add_str('')
479 |
480 | !get optional inputs (if not present, set default value):
481 | call optional_int_to_string(bins, binsstr, '10')
482 | call optional_logical_to_string(cumulative, cumulativestr, 'False')
483 |
484 | !write the plot statement:
485 | call me%add_str('ax.hist('//&
486 | trim(xname)//','//&
487 | 'label='//trim(me%raw_str_token)//'"'//trim(label)//'",'//&
488 | 'bins='//trim(binsstr)//','//&
489 | 'cumulative='//trim(cumulativestr)//')')
490 |
491 | !axis limits:
492 | if (allocated(xlimstr)) call me%add_str('ax.set_xlim('//xlimstr//')')
493 | if (allocated(ylimstr)) call me%add_str('ax.set_ylim('//ylimstr//')')
494 |
495 | !axis scales:
496 | if (present(xscale)) call me%add_str('ax.set_xscale('//trim(me%raw_str_token)//'"'//xscale//'")')
497 | if (present(yscale)) call me%add_str('ax.set_yscale('//trim(me%raw_str_token)//'"'//yscale//'")')
498 |
499 | call me%add_str('')
500 |
501 | else
502 | if (present(istat)) istat = -1
503 | write(error_unit,'(A)') 'Error in add_plot: pyplot class not properly initialized.'
504 | end if
505 |
506 | end subroutine add_hist
507 | !*****************************************************************************************
508 |
509 | !*****************************************************************************************
510 | !> author: Jacob Williams
511 | !
512 | ! Add a contour plot.
513 | !
514 | !@note This requires `use_numpy` to be True.
515 |
516 | subroutine add_contour(me, x, y, z, linestyle, linewidth, levels, color, &
517 | filled, cmap, colorbar, istat)
518 |
519 | class(pyplot), intent (inout) :: me !! pyplot handler
520 | real(wp),dimension(:), intent (in) :: x !! x values
521 | real(wp),dimension(:), intent (in) :: y !! y values
522 | real(wp),dimension(:,:), intent (in) :: z !! z values (a matrix)
523 | character(len=*), intent (in) :: linestyle !! style of the plot line
524 | integer, intent (in), optional :: linewidth !! width of the plot line [only used when `filled=False`]
525 | real(wp),dimension(:), intent (in), optional :: levels !! contour levels to plot
526 | character(len=*), intent (in), optional :: color !! color of the contour line
527 | logical, intent (in), optional :: filled !! use filled control (default=False)
528 | character(len=*), intent (in), optional :: cmap !! colormap if filled=True (examples: 'jet', 'bone')
529 | logical, intent (in), optional :: colorbar !! add a colorbar (default=False)
530 | integer, intent (out),optional :: istat !! status output (0 means no problems)
531 |
532 | character(len=:), allocatable :: xstr !! x values stringified
533 | character(len=:), allocatable :: ystr !! y values stringified
534 | character(len=:), allocatable :: zstr !! z values stringified
535 | character(len=:), allocatable :: levelstr !! levels vector stringified
536 | character(len=max_int_len) :: iline !! actual line width
537 | character(len=*), parameter :: xname = 'x' !! x variable name for script
538 | character(len=*), parameter :: yname = 'y' !! y variable name for script
539 | character(len=*), parameter :: zname = 'z' !! z variable name for script
540 | character(len=*), parameter :: xname_ = 'X' !! X variable name for contour
541 | character(len=*), parameter :: yname_ = 'Y' !! Y variable name for contour
542 | character(len=*), parameter :: zname_ = 'Z' !! Z variable name for contour
543 | character(len=:), allocatable :: extras !! optional stuff
544 | character(len=:), allocatable :: contourfunc !! 'contour' or 'contourf'
545 | logical :: is_filled !! if it is a filled contour plot
546 |
547 | if (allocated(me%str)) then
548 |
549 | if (present(istat)) istat = 0
550 |
551 | !convert the arrays to strings:
552 | call vec_to_string(x, me%real_fmt, xstr, me%use_numpy)
553 | call vec_to_string(y, me%real_fmt, ystr, me%use_numpy)
554 | call matrix_to_string(z, me%real_fmt, zstr, me%use_numpy)
555 | if (present(levels)) call vec_to_string(levels, me%real_fmt, levelstr, me%use_numpy)
556 |
557 | !get optional inputs (if not present, set default value):
558 | call optional_int_to_string(linewidth, iline, '3')
559 |
560 | !write the arrays:
561 | call me%add_str(trim(xname)//' = '//xstr)
562 | call me%add_str(trim(yname)//' = '//ystr)
563 | call me%add_str(trim(zname)//' = '//zstr)
564 | call me%add_str('')
565 |
566 | !convert inputs for contour plotting:
567 | call me%add_str(xname_//', '//yname_//' = np.meshgrid('//trim(xname)//', '//trim(yname)//')')
568 | call me%add_str(zname_//' = np.transpose('//zname//')')
569 |
570 | !optional arguments:
571 | extras = ''
572 | if (present(levels)) extras = extras//','//'levels='//levelstr
573 | if (present(color)) extras = extras//','//'colors='//trim(me%raw_str_token)//'"'//color//'"'
574 | if (present(linewidth)) extras = extras//','//'linewidths='//trim(adjustl(iline))
575 | if (present(cmap)) extras = extras//','//'cmap='//trim(me%raw_str_token)//'"'//cmap//'"'
576 |
577 | !filled or regular:
578 | contourfunc = 'contour' !default
579 | is_filled = .false.
580 | if (present(filled)) then
581 | is_filled = filled
582 | if (filled) contourfunc = 'contourf' !filled contour
583 | end if
584 |
585 | !write the plot statement:
586 | call me%add_str('CS = ax.'//contourfunc//'('//xname_//','//yname_//','//zname_//','//&
587 | 'linestyles='//trim(me%raw_str_token)//'"'//trim(adjustl(linestyle))//'"'//&
588 | extras//')')
589 |
590 | if (present(colorbar)) then
591 | if (colorbar) call me%add_str('fig.colorbar(CS)')
592 | end if
593 |
594 | if (.not. is_filled) call me%add_str('ax.clabel(CS, fontsize=9, inline=1)')
595 | call me%add_str('')
596 |
597 | else
598 | if (present(istat)) istat = -1
599 | write(error_unit,'(A)') 'Error in add_plot: pyplot class not properly initialized.'
600 | end if
601 |
602 | end subroutine add_contour
603 | !*****************************************************************************************
604 |
605 | !*****************************************************************************************
606 | !> author: Jacob Williams
607 | !
608 | ! Add a surface plot.
609 | !
610 | !@note This requires `use_numpy` to be True.
611 |
612 | subroutine plot_surface(me, x, y, z, label, linestyle, linewidth, levels, color, &
613 | cmap, colorbar, antialiased, istat)
614 |
615 | class(pyplot), intent (inout) :: me !! pyplot handler
616 | real(wp),dimension(:), intent (in) :: x !! x values
617 | real(wp),dimension(:), intent (in) :: y !! y values
618 | real(wp),dimension(:,:), intent (in) :: z !! z values (a matrix)
619 | character(len=*), intent (in) :: label !! plot label
620 | character(len=*), intent (in) :: linestyle !! style of the plot line
621 | integer, intent (in), optional :: linewidth !! width of the plot line
622 | real(wp),dimension(:), intent (in), optional :: levels !! contour levels to plot
623 | character(len=*), intent (in), optional :: color !! Color of the surface patches
624 | character(len=*), intent (in), optional :: cmap !! colormap if filled=True (examples: 'jet', 'bone')
625 | logical, intent (in), optional :: colorbar !! add a colorbar (default=False)
626 | logical, intent (in), optional :: antialiased !! The surface is made opaque by using antialiased=False
627 | integer, intent (out), optional :: istat !! status output (0 means no problems)
628 |
629 | character(len=:), allocatable :: xstr !! x values stringified
630 | character(len=:), allocatable :: ystr !! y values stringified
631 | character(len=:), allocatable :: zstr !! z values stringified
632 | character(len=:), allocatable :: levelstr !! levels vector stringified
633 | character(len=:), allocatable :: antialiasedstr !! antialiased stringified
634 | character(len=max_int_len) :: iline !! actual line width
635 | character(len=*), parameter :: xname = 'x' !! x variable name for script
636 | character(len=*), parameter :: yname = 'y' !! y variable name for script
637 | character(len=*), parameter :: zname = 'z' !! z variable name for script
638 | character(len=*), parameter :: xname_ = 'X' !! X variable name for contour
639 | character(len=*), parameter :: yname_ = 'Y' !! Y variable name for contour
640 | character(len=*), parameter :: zname_ = 'Z' !! Z variable name for contour
641 | character(len=:), allocatable :: extras !! optional stuff
642 |
643 | if (allocated(me%str)) then
644 |
645 | if (present(istat)) istat = 0
646 |
647 | !convert the arrays to strings:
648 | call vec_to_string(x, me%real_fmt, xstr, me%use_numpy)
649 | call vec_to_string(y, me%real_fmt, ystr, me%use_numpy)
650 | call matrix_to_string(z, me%real_fmt, zstr, me%use_numpy)
651 | if (present(levels)) call vec_to_string(levels, me%real_fmt, levelstr, me%use_numpy)
652 |
653 | !get optional inputs (if not present, set default value):
654 | call optional_int_to_string(linewidth, iline, '3')
655 | call optional_logical_to_string(antialiased, antialiasedstr, 'False')
656 |
657 | !write the arrays:
658 | call me%add_str(trim(xname)//' = '//xstr)
659 | call me%add_str(trim(yname)//' = '//ystr)
660 | call me%add_str(trim(zname)//' = '//zstr)
661 | call me%add_str('')
662 |
663 | !convert inputs for contour plotting:
664 | call me%add_str(xname_//', '//yname_//' = np.meshgrid('//trim(xname)//', '//trim(yname)//')')
665 | call me%add_str(zname_//' = np.transpose('//zname//')')
666 |
667 | !optional arguments:
668 | extras = ''
669 | if (present(levels)) extras = extras//','//'levels='//levelstr
670 | if (present(color)) extras = extras//','//'colors='//trim(me%raw_str_token)//'"'//color//'"'
671 | if (present(linewidth)) extras = extras//','//'linewidths='//trim(adjustl(iline))
672 | if (present(cmap)) extras = extras//','//'cmap='//trim(me%raw_str_token)//'"'//cmap//'"'
673 |
674 | !write the plot statement:
675 | call me%add_str('CS = ax.plot_surface'//'('//xname_//','//yname_//','//zname_//','//&
676 | 'label='//trim(me%raw_str_token)//'"'//trim(label)//'",'//&
677 | 'antialiased='//trim(antialiasedstr)//','//&
678 | 'linestyles='//trim(me%raw_str_token)//'"'//trim(adjustl(linestyle))//'"'//&
679 | extras//')')
680 |
681 | if (present(colorbar)) then
682 | if (colorbar) call me%add_str('fig.colorbar(CS)')
683 | end if
684 |
685 | call me%add_str('')
686 |
687 | else
688 | if (present(istat)) istat = -1
689 | write(error_unit,'(A)') 'Error in add_plot: pyplot class not properly initialized.'
690 | end if
691 |
692 | end subroutine plot_surface
693 | !*****************************************************************************************
694 |
695 | !*****************************************************************************************
696 | !> author: Jacob Williams
697 | !
698 | ! Add a wireframe plot.
699 | !
700 | !@note This requires `use_numpy` to be True.
701 |
702 | subroutine plot_wireframe(me, x, y, z, label, linestyle, linewidth, levels, color, &
703 | cmap, colorbar, antialiased, istat)
704 |
705 | class(pyplot), intent (inout) :: me !! pyplot handler
706 | real(wp),dimension(:), intent (in) :: x !! x values
707 | real(wp),dimension(:), intent (in) :: y !! y values
708 | real(wp),dimension(:,:), intent (in) :: z !! z values (a matrix)
709 | character(len=*), intent (in) :: label !! plot label
710 | character(len=*), intent (in) :: linestyle !! style of the plot line
711 | integer, intent (in), optional :: linewidth !! width of the plot line
712 | real(wp),dimension(:), intent (in), optional :: levels !! contour levels to plot
713 | character(len=*), intent (in), optional :: color !! Color of the surface patches
714 | character(len=*), intent (in), optional :: cmap !! colormap if filled=True (examples: 'jet', 'bone')
715 | logical, intent (in), optional :: colorbar !! add a colorbar (default=False)
716 | logical, intent (in), optional :: antialiased !! The surface is made opaque by using antialiased=False
717 | integer, intent (out), optional :: istat !! status output (0 means no problems)
718 |
719 | character(len=:), allocatable :: xstr !! x values stringified
720 | character(len=:), allocatable :: ystr !! y values stringified
721 | character(len=:), allocatable :: zstr !! z values stringified
722 | character(len=:), allocatable :: levelstr !! levels vector stringified
723 | character(len=:), allocatable :: antialiasedstr !! antialiased stringified
724 | character(len=max_int_len) :: iline !! actual line width
725 | character(len=*), parameter :: xname = 'x' !! x variable name for script
726 | character(len=*), parameter :: yname = 'y' !! y variable name for script
727 | character(len=*), parameter :: zname = 'z' !! z variable name for script
728 | character(len=*), parameter :: xname_ = 'X' !! X variable name for contour
729 | character(len=*), parameter :: yname_ = 'Y' !! Y variable name for contour
730 | character(len=*), parameter :: zname_ = 'Z' !! Z variable name for contour
731 | character(len=:), allocatable :: extras !! optional stuff
732 |
733 | if (allocated(me%str)) then
734 |
735 | if (present(istat)) istat = 0
736 |
737 | !convert the arrays to strings:
738 | call vec_to_string(x, me%real_fmt, xstr, me%use_numpy)
739 | call vec_to_string(y, me%real_fmt, ystr, me%use_numpy)
740 | call matrix_to_string(z, me%real_fmt, zstr, me%use_numpy)
741 | if (present(levels)) call vec_to_string(levels, me%real_fmt, levelstr, me%use_numpy)
742 |
743 | !get optional inputs (if not present, set default value):
744 | call optional_int_to_string(linewidth, iline, '3')
745 | call optional_logical_to_string(antialiased, antialiasedstr, 'False')
746 |
747 | !write the arrays:
748 | call me%add_str(trim(xname)//' = '//xstr)
749 | call me%add_str(trim(yname)//' = '//ystr)
750 | call me%add_str(trim(zname)//' = '//zstr)
751 | call me%add_str('')
752 |
753 | !convert inputs for contour plotting:
754 | call me%add_str(xname_//', '//yname_//' = np.meshgrid('//trim(xname)//', '//trim(yname)//')')
755 | call me%add_str(zname_//' = np.transpose('//zname//')')
756 |
757 | !optional arguments:
758 | extras = ''
759 | if (present(levels)) extras = extras//','//'levels='//levelstr
760 | if (present(color)) extras = extras//','//'colors='//trim(me%raw_str_token)//'"'//color//'"'
761 | if (present(linewidth)) extras = extras//','//'linewidths='//trim(adjustl(iline))
762 | if (present(cmap)) extras = extras//','//'cmap='//trim(me%raw_str_token)//'"'//cmap//'"'
763 |
764 | !write the plot statement:
765 | call me%add_str('CS = ax.plot_wireframe'//'('//xname_//','//yname_//','//zname_//','//&
766 | 'label='//trim(me%raw_str_token)//'"'//trim(label)//'",'//&
767 | 'antialiased='//trim(antialiasedstr)//','//&
768 | 'linestyles='//trim(me%raw_str_token)//'"'//trim(adjustl(linestyle))//'"'//&
769 | extras//')')
770 |
771 | if (present(colorbar)) then
772 | if (colorbar) call me%add_str('fig.colorbar(CS)')
773 | end if
774 |
775 | call me%add_str('')
776 |
777 | else
778 | if (present(istat)) istat = -1
779 | write(error_unit,'(A)') 'Error in add_plot: pyplot class not properly initialized.'
780 | end if
781 |
782 | end subroutine plot_wireframe
783 | !*****************************************************************************************
784 |
785 | !*****************************************************************************************
786 | !> author: Jacob Williams
787 | !
788 | ! Add a 3D x,y,z plot.
789 | !
790 | !@note Must initialize the class with ```mplot3d=.true.```
791 |
792 | subroutine add_3d_plot(me, x, y, z, label, linestyle, markersize, linewidth, istat)
793 |
794 | class(pyplot), intent (inout) :: me !! pyplot handler
795 | real(wp), dimension(:), intent (in) :: x !! x values
796 | real(wp), dimension(:), intent (in) :: y !! y values
797 | real(wp), dimension(:), intent (in) :: z !! z values
798 | character(len=*), intent (in) :: label !! plot label
799 | character(len=*), intent (in) :: linestyle !! style of the plot line
800 | integer, intent (in), optional :: markersize !! size of the plot markers
801 | integer, intent (in), optional :: linewidth !! width of the plot line
802 | integer, intent (out), optional :: istat !! status output (0 means no problems)
803 |
804 | character(len=:), allocatable :: xstr !! x values stringified
805 | character(len=:), allocatable :: ystr !! y values stringified
806 | character(len=:), allocatable :: zstr !! z values stringified
807 | character(len=max_int_len) :: imark !! actual markers size
808 | character(len=max_int_len) :: iline !! actual line width
809 | character(len=*), parameter :: xname = 'x' !! x variable name for script
810 | character(len=*), parameter :: yname = 'y' !! y variable name for script
811 | character(len=*), parameter :: zname = 'z' !! z variable name for script
812 |
813 | if (allocated(me%str)) then
814 |
815 | if (present(istat)) istat = 0
816 |
817 | !convert the arrays to strings:
818 | call vec_to_string(x, me%real_fmt, xstr, me%use_numpy)
819 | call vec_to_string(y, me%real_fmt, ystr, me%use_numpy)
820 | call vec_to_string(z, me%real_fmt, zstr, me%use_numpy)
821 |
822 | !get optional inputs (if not present, set default value):
823 | call optional_int_to_string(markersize, imark, '3')
824 | call optional_int_to_string(linewidth, iline, '3')
825 |
826 | !write the arrays:
827 | call me%add_str(trim(xname)//' = '//xstr)
828 | call me%add_str(trim(yname)//' = '//ystr)
829 | call me%add_str(trim(zname)//' = '//zstr)
830 | call me%add_str('')
831 |
832 | !write the plot statement:
833 | call me%add_str('ax.plot('//&
834 | trim(xname)//','//&
835 | trim(yname)//','//&
836 | trim(zname)//','//&
837 | trim(me%raw_str_token)//'"'//trim(linestyle)//'",'//&
838 | 'linewidth='//trim(adjustl(iline))//','//&
839 | 'markersize='//trim(adjustl(imark))//','//&
840 | 'label='//trim(me%raw_str_token)//'"'//trim(label)//'")')
841 | call me%add_str('')
842 |
843 | else
844 | if (present(istat)) istat = -1
845 | write(error_unit,'(A)') 'Error in add_3d_plot: pyplot class not properly initialized.'
846 | end if
847 |
848 | end subroutine add_3d_plot
849 | !*****************************************************************************************
850 |
851 | !*****************************************************************************************
852 | !> author: Jacob Williams
853 | !
854 | ! Add a sphere to a 3D x,y,z plot.
855 | !
856 | !@note Must initialize the class with `mplot3d=.true.` and `use_numpy=.true.`.
857 |
858 | subroutine add_sphere(me, r, xc, yc, zc, n_facets, linewidth, antialiased, color, istat)
859 |
860 | implicit none
861 |
862 | class(pyplot), intent (inout) :: me !! pyplot handler
863 | real(wp), intent (in) :: r !! radius of the sphere
864 | real(wp), intent (in) :: xc !! x value of sphere center
865 | real(wp), intent (in) :: yc !! y value of sphere center
866 | real(wp), intent (in) :: zc !! z value of sphere center
867 | integer, intent (in), optional :: n_facets !! [default is 100]
868 | integer, intent (in), optional :: linewidth !! line width
869 | logical, intent (in), optional :: antialiased !! enabled anti-aliasing
870 | character(len=*), intent (in), optional :: color !! color of the contour line
871 | integer, intent (out), optional :: istat !! status output (0 means no problems)
872 |
873 | character(len=:), allocatable :: rstr !! `r` value stringified
874 | character(len=:), allocatable :: xcstr !! `xc` value stringified
875 | character(len=:), allocatable :: ycstr !! `yc` value stringified
876 | character(len=:), allocatable :: zcstr !! `zc` value stringified
877 | character(len=*), parameter :: xname = 'x' !! `x` variable name for script
878 | character(len=*), parameter :: yname = 'y' !! `y` variable name for script
879 | character(len=*), parameter :: zname = 'z' !! `z` variable name for script
880 |
881 | character(len=max_int_len) :: linewidth_str !! `linewidth` input stringified
882 | character(len=:), allocatable :: antialiased_str !! `antialised` input stringified
883 | character(len=max_int_len) :: n_facets_str !! `n_facets` input stringified
884 | character(len=:), allocatable :: extras !! optional stuff string
885 |
886 | if (allocated(me%str)) then
887 |
888 | !get optional inputs (if not present, set default value):
889 | call optional_int_to_string(n_facets, n_facets_str, '100')
890 | extras = ''
891 | if (present(linewidth)) then
892 | call optional_int_to_string(linewidth, linewidth_str, '1')
893 | extras = extras//','//'linewidth='//linewidth_str
894 | end if
895 | if (present(antialiased)) then
896 | call optional_logical_to_string(antialiased, antialiased_str, 'False')
897 | extras = extras//','//'antialiased='//antialiased_str
898 | end if
899 | if (present(color)) then
900 | extras = extras//','//'color='//trim(me%raw_str_token)//'"'//trim(color)//'"'
901 | end if
902 |
903 | if (present(istat)) istat = 0
904 |
905 | !convert the arrays to strings:
906 | call real_to_string(r , me%real_fmt, rstr)
907 | call real_to_string(xc, me%real_fmt, xcstr)
908 | call real_to_string(yc, me%real_fmt, ycstr)
909 | call real_to_string(zc, me%real_fmt, zcstr)
910 |
911 | ! sphere code:
912 | call me%add_str('u = np.linspace(0, 2 * np.pi, '//n_facets_str//')')
913 | call me%add_str('v = np.linspace(0, np.pi, '//n_facets_str//')')
914 | call me%add_str(xname//' = '//xcstr//' + '//rstr//' * np.outer(np.cos(u), np.sin(v))')
915 | call me%add_str(yname//' = '//ycstr//' + '//rstr//' * np.outer(np.sin(u), np.sin(v))')
916 | call me%add_str(zname//' = '//zcstr//' + '//rstr//' * np.outer(np.ones(np.size(u)), np.cos(v))')
917 | call me%add_str('ax.plot_surface('//xname//', '//yname//', '//zname//extras//')')
918 | call me%add_str('')
919 |
920 | else
921 | if (present(istat)) istat = -1
922 | write(error_unit,'(A)') 'Error in add_sphere: pyplot class not properly initialized.'
923 | end if
924 |
925 | end subroutine add_sphere
926 | !*****************************************************************************************
927 |
928 | !*****************************************************************************************
929 | !> author: Jacob Williams
930 | !
931 | ! Add a bar plot.
932 |
933 | subroutine add_bar(me, x, height, label, width, bottom, color, &
934 | yerr, align, xlim, ylim, xscale, yscale, istat)
935 |
936 | class(pyplot), intent(inout) :: me !! pyplot handler
937 | real(wp), dimension(:), intent(in) :: x !! x bar values
938 | real(wp), dimension(:), intent(in) :: height !! height bar values
939 | character(len=*), intent(in) :: label !! plot label
940 | real(wp), dimension(:), intent(in), optional :: width !! width values
941 | real(wp), dimension(:), intent(in), optional :: bottom !! bottom values
942 | character(len=*), intent(in), optional :: color !! plot color
943 | real(wp), dimension(:), intent(in), optional :: yerr !! yerr values
944 | character(len=*), intent(in), optional :: align !! default: 'center'
945 | real(wp),dimension(2), intent (in), optional :: xlim !! x-axis range
946 | real(wp),dimension(2), intent (in), optional :: ylim !! y-axis range
947 | character(len=*), intent (in), optional :: xscale !! example: 'linear' (default), 'log'
948 | character(len=*), intent (in), optional :: yscale !! example: 'linear' (default), 'log'
949 | integer, intent (out),optional :: istat !! status output (0 means no problems)
950 |
951 | character(len=:), allocatable :: xstr !! x axis values stringified
952 | character(len=:), allocatable :: ystr !! y axis values stringified
953 | character(len=:), allocatable :: xlimstr !! xlim values stringified
954 | character(len=:), allocatable :: ylimstr !! ylim values stringified
955 | character(len=:), allocatable :: wstr !! width values stringified
956 | character(len=:), allocatable :: bstr !! bottom values stringified
957 | character(len=:), allocatable :: plt_str !! plot string
958 | character(len=:), allocatable :: yerr_str !! yerr values stringified
959 | character(len=*), parameter :: xname = 'x' !! x axis name
960 | character(len=*), parameter :: yname = 'y' !! y axis name
961 | character(len=*), parameter :: wname = 'w' !! width name
962 | character(len=*), parameter :: bname = 'b' !! bottom name
963 | character(len=*), parameter :: yerrname = 'yerr' !! yerr name
964 |
965 | if (allocated(me%str)) then
966 |
967 | if (present(istat)) istat = 0
968 |
969 | !axis limits (optional):
970 | if (present(xlim)) call vec_to_string(xlim, me%real_fmt, xlimstr, me%use_numpy)
971 | if (present(ylim)) call vec_to_string(ylim, me%real_fmt, ylimstr, me%use_numpy)
972 |
973 | !convert the arrays to strings:
974 | call vec_to_string(x, me%real_fmt, xstr, me%use_numpy)
975 | call vec_to_string(height, me%real_fmt, ystr, me%use_numpy)
976 | if (present(width)) call vec_to_string(width, me%real_fmt, wstr, me%use_numpy)
977 | if (present(bottom)) call vec_to_string(bottom, me%real_fmt, bstr, me%use_numpy)
978 | if (present(yerr)) call vec_to_string(yerr, me%real_fmt, yerr_str, me%use_numpy)
979 |
980 | !write the arrays:
981 | call me%add_str(trim(xname)//' = '//xstr)
982 | call me%add_str(trim(yname)//' = '//ystr)
983 | if (present(width)) call me%add_str(trim(wname)//' = '//wstr)
984 | if (present(bottom)) call me%add_str(trim(bname)//' = '//bstr)
985 | if (present(yerr)) call me%add_str(trim(yerrname)//' = '//yerr_str)
986 | call me%add_str('')
987 |
988 | !create the plot string:
989 | plt_str = 'ax.bar('//&
990 | 'x='//trim(xname)//','//&
991 | 'height='//trim(yname)//','
992 | if (present(yerr)) plt_str=plt_str//'yerr='//trim(yerrname)//','
993 | if (present(width)) plt_str=plt_str//'width='//trim(wname)//','
994 | if (present(bottom)) plt_str=plt_str//'bottom='//trim(bstr)//','
995 | if (present(color)) plt_str=plt_str//'color='//trim(me%raw_str_token)//'"'//trim(color)//'",'
996 | if (present(align)) plt_str=plt_str//'align='//trim(me%raw_str_token)//'"'//trim(align)//'",'
997 | plt_str=plt_str//'label='//trim(me%raw_str_token)//'"'//trim(label)//'")'
998 |
999 | !write the plot statement:
1000 | call me%add_str(plt_str)
1001 |
1002 | !axis limits:
1003 | if (allocated(xlimstr)) call me%add_str('ax.set_xlim('//xlimstr//')')
1004 | if (allocated(ylimstr)) call me%add_str('ax.set_ylim('//ylimstr//')')
1005 |
1006 | !axis scales:
1007 | if (present(xscale)) call me%add_str('ax.set_xscale('//trim(me%raw_str_token)//'"'//xscale//'")')
1008 | if (present(yscale)) call me%add_str('ax.set_yscale('//trim(me%raw_str_token)//'"'//yscale//'")')
1009 |
1010 | call me%add_str('')
1011 |
1012 | else
1013 | if (present(istat)) istat = -1
1014 | write(error_unit,'(A)') 'Error in add_bar: pyplot class not properly initialized.'
1015 | end if
1016 |
1017 | end subroutine add_bar
1018 | !*****************************************************************************************
1019 |
1020 | !*****************************************************************************************
1021 | !>
1022 | ! Add an image plot using `imshow`.
1023 | !
1024 | !### Note
1025 | ! * Based on code by Ricardo Torres, 4/2/2017.
1026 |
1027 | subroutine add_imshow(me, x, xlim, ylim, istat)
1028 |
1029 | class(pyplot), intent (inout) :: me !! pyplot handler
1030 | real(wp),dimension(:,:),intent (in) :: x !! x values
1031 | real(wp),dimension(2), intent (in), optional :: xlim !! x-axis range
1032 | real(wp),dimension(2), intent (in), optional :: ylim !! y-axis range
1033 | integer, intent (out),optional :: istat !! status output (0 means no problems)
1034 |
1035 | character(len=:), allocatable :: xstr !! x values stringified
1036 | character(len=*), parameter :: xname = 'x' !! x variable name for script
1037 |
1038 | !axis limits (optional):
1039 | character(len=:), allocatable :: xlimstr !! xlim values stringified
1040 | character(len=:), allocatable :: ylimstr !! ylim values stringified
1041 |
1042 | if (allocated(me%str)) then
1043 |
1044 | if (present(istat)) istat = 0
1045 |
1046 | if (present(xlim)) call vec_to_string(xlim, me%real_fmt, xlimstr, me%use_numpy)
1047 | if (present(ylim)) call vec_to_string(ylim, me%real_fmt, ylimstr, me%use_numpy)
1048 |
1049 | !convert the arrays to strings:
1050 | call matrix_to_string(x, me%real_fmt, xstr, me%use_numpy)
1051 |
1052 | !write the arrays:
1053 | call me%add_str(trim(xname)//' = '//xstr)
1054 | call me%add_str('')
1055 |
1056 | !write the plot statement:
1057 | call me%add_str('ax.imshow('//trim(xname)//')')
1058 | call me%add_str('')
1059 |
1060 | !axis limits:
1061 | if (allocated(xlimstr)) call me%add_str('ax.set_xlim('//xlimstr//')')
1062 | if (allocated(ylimstr)) call me%add_str('ax.set_ylim('//ylimstr//')')
1063 |
1064 | else
1065 | if (present(istat)) istat = -1
1066 | write(error_unit,'(A)') 'Error in add_imshow: pyplot class not properly initialized.'
1067 | end if
1068 |
1069 | end subroutine add_imshow
1070 | !*****************************************************************************************
1071 |
1072 | !*****************************************************************************************
1073 | !> author: Alexander Sandrock
1074 | !
1075 | ! Add an x,y plot with errorbars.
1076 |
1077 | subroutine add_errorbar(me, x, y, label, linestyle, xerr, yerr, markersize, linewidth, xlim, ylim, xscale, yscale, color, istat)
1078 |
1079 | class(pyplot), intent (inout) :: me !! pyplot handler
1080 | real(wp), dimension(:), intent (in) :: x !! x values
1081 | real(wp), dimension(:), intent (in) :: y !! y values
1082 | character(len=*), intent (in) :: label !! plot label
1083 | character(len=*), intent (in) :: linestyle !! style of the plot line
1084 | real(wp), dimension(:), intent (in), optional :: xerr !! x errorbar sizes
1085 | real(wp), dimension(:), intent (in), optional :: yerr !! y errorbar sizes
1086 | integer, intent (in), optional :: markersize !! size of the plot markers
1087 | integer, intent (in), optional :: linewidth !! width of the plot line
1088 | real(wp),dimension(2), intent (in), optional :: xlim !! x-axis range
1089 | real(wp),dimension(2), intent (in), optional :: ylim !! y-axis range
1090 | character(len=*), intent (in), optional :: xscale !! example: 'linear' (default), 'log'
1091 | character(len=*), intent (in), optional :: yscale !! example: 'linear' (default), 'log'
1092 | real(wp),dimension(:), intent (in), optional :: color !! RGB color tuple [0-1,0-1,0-1]
1093 | integer, intent (out),optional :: istat !! status output (0 means no problems)
1094 |
1095 | character(len=:), allocatable :: arg_str !! the arguments to pass to `plot`
1096 | character(len=:), allocatable :: xstr !! x values stringified
1097 | character(len=:), allocatable :: ystr !! y values stringified
1098 | character(len=:), allocatable :: xlimstr !! xlim values stringified
1099 | character(len=:), allocatable :: ylimstr !! ylim values stringified
1100 | character(len=:), allocatable :: xerrstr !! xerr values stringified
1101 | character(len=:), allocatable :: yerrstr !! yerr values stringified
1102 | character(len=:), allocatable :: color_str !! color values stringified
1103 | character(len=max_int_len) :: imark !! actual markers size
1104 | character(len=max_int_len) :: iline !! actual line width
1105 | character(len=*), parameter :: xname = 'x' !! x variable name for script
1106 | character(len=*), parameter :: yname = 'y' !! y variable name for script
1107 | character(len=*), parameter :: xerrname = 'xerr' !! xerr variable name for script
1108 | character(len=*), parameter :: yerrname = 'yerr' !! yerr variable name for script
1109 |
1110 | if (allocated(me%str)) then
1111 |
1112 | if (present(istat)) istat = 0
1113 |
1114 | !axis limits (optional):
1115 | if (present(xlim)) call vec_to_string(xlim, me%real_fmt, xlimstr, me%use_numpy)
1116 | if (present(ylim)) call vec_to_string(ylim, me%real_fmt, ylimstr, me%use_numpy)
1117 | !errorbar sizes (optional):
1118 | if (present(xerr)) call vec_to_string(xerr, me%real_fmt, xerrstr, me%use_numpy)
1119 | if (present(yerr)) call vec_to_string(yerr, me%real_fmt, yerrstr, me%use_numpy)
1120 |
1121 | !convert the arrays to strings:
1122 | call vec_to_string(x, me%real_fmt, xstr, me%use_numpy)
1123 | call vec_to_string(y, me%real_fmt, ystr, me%use_numpy)
1124 |
1125 | !get optional inputs (if not present, set default value):
1126 | call optional_int_to_string(markersize, imark, '3')
1127 | call optional_int_to_string(linewidth, iline, '3')
1128 |
1129 | !write the arrays:
1130 | call me%add_str(trim(xname)//' = '//xstr)
1131 | call me%add_str(trim(yname)//' = '//ystr)
1132 | call me%add_str('')
1133 | if (present(xerr)) call me%add_str(trim(xerrname)//' = '//xerrstr)
1134 | if (present(yerr)) call me%add_str(trim(yerrname)//' = '//yerrstr)
1135 | if (present(xerr) .or. present(yerr)) call me%add_str('')
1136 |
1137 | !main arguments for plot:
1138 | arg_str = trim(xname)//','//&
1139 | trim(yname)//','//&
1140 | 'fmt='//trim(me%raw_str_token)//'"'//trim(linestyle)//'",'//&
1141 | 'linewidth='//trim(adjustl(iline))//','//&
1142 | 'markersize='//trim(adjustl(imark))//','//&
1143 | 'label='//trim(me%raw_str_token)//'"'//trim(label)//'"'
1144 |
1145 | ! optional arguments:
1146 | if (present(xerr)) then
1147 | arg_str = arg_str//','//'xerr='//trim(xerrname)
1148 | end if
1149 | if (present(yerr)) then
1150 | arg_str = arg_str//','//'yerr='//trim(yerrname)
1151 | end if
1152 | if (present(color)) then
1153 | if (size(color)<=3) then
1154 | call vec_to_string(color(1:3), '*', color_str, use_numpy=.false., is_tuple=.true.)
1155 | arg_str = arg_str//',color='//trim(color_str)
1156 | end if
1157 | end if
1158 |
1159 | !write the plot statement:
1160 | call me%add_str('ax.errorbar('//arg_str//')')
1161 |
1162 | !axis limits:
1163 | if (allocated(xlimstr)) call me%add_str('ax.set_xlim('//xlimstr//')')
1164 | if (allocated(ylimstr)) call me%add_str('ax.set_ylim('//ylimstr//')')
1165 |
1166 | !axis scales:
1167 | if (present(xscale)) call me%add_str('ax.set_xscale('//trim(me%raw_str_token)//'"'//xscale//'")')
1168 | if (present(yscale)) call me%add_str('ax.set_yscale('//trim(me%raw_str_token)//'"'//yscale//'")')
1169 |
1170 | call me%add_str('')
1171 |
1172 | else
1173 | if (present(istat)) istat = -1
1174 | write(error_unit,'(A)') 'Error in add_errorbar: pyplot class not properly initialized.'
1175 | end if
1176 |
1177 | end subroutine add_errorbar
1178 | !*****************************************************************************************
1179 |
1180 | !*****************************************************************************************
1181 | !> author: Jacob Williams
1182 | !
1183 | ! Integer to string, specifying the default value if
1184 | ! the optional argument is not present.
1185 |
1186 | subroutine optional_int_to_string(int_value, string_value, default_value)
1187 |
1188 | integer, intent(in), optional :: int_value !! integer value
1189 | character(len=*), intent(out) :: string_value !! integer value stringified
1190 | character(len=*), intent(in) :: default_value !! default integer value
1191 |
1192 | if (present(int_value)) then
1193 | call integer_to_string(int_value, string_value)
1194 | else
1195 | string_value = default_value
1196 | end if
1197 |
1198 | end subroutine optional_int_to_string
1199 | !*****************************************************************************************
1200 |
1201 | !*****************************************************************************************
1202 | !> author: Jacob Williams
1203 | !
1204 | ! Logical to string, specifying the default value if
1205 | ! the optional argument is not present.
1206 |
1207 | subroutine optional_logical_to_string(logical_value, string_value, default_value)
1208 |
1209 | logical,intent(in),optional :: logical_value
1210 | character(len=:),allocatable,intent(out) :: string_value !! integer value stringified
1211 | character(len=*),intent(in) :: default_value !! default integer value
1212 |
1213 | if (present(logical_value)) then
1214 | if (logical_value) then
1215 | string_value = 'True'
1216 | else
1217 | string_value = 'False'
1218 | end if
1219 | else
1220 | string_value = default_value
1221 | end if
1222 |
1223 | end subroutine optional_logical_to_string
1224 | !*****************************************************************************************
1225 |
1226 | !*****************************************************************************************
1227 | !> author: Jacob Williams
1228 | !
1229 | ! Integer to string conversion.
1230 |
1231 | subroutine integer_to_string(i, s)
1232 |
1233 | integer, intent(in), optional :: i !! integer value
1234 | character(len=*), intent(out) :: s !! integer value stringified
1235 |
1236 | integer :: istat !! IO status
1237 |
1238 | write(s, int_fmt, iostat=istat) i
1239 |
1240 | if (istat/=0) then
1241 | write(error_unit,'(A)') 'Error converting integer to string'
1242 | s = '****'
1243 | else
1244 | s = adjustl(s)
1245 | end if
1246 |
1247 | end subroutine integer_to_string
1248 | !*****************************************************************************************
1249 |
1250 | !*****************************************************************************************
1251 | !> author: Jacob Williams
1252 | !
1253 | ! Real scalar to string.
1254 |
1255 | subroutine real_to_string(v, fmt, str)
1256 |
1257 | real(wp), intent(in) :: v !! real values
1258 | character(len=*), intent(in) :: fmt !! real format string
1259 | character(len=:), allocatable, intent(out) :: str !! real values stringified
1260 |
1261 | integer :: istat !! IO status
1262 | character(len=max_real_len) :: tmp !! dummy string
1263 |
1264 | if (fmt=='*') then
1265 | write(tmp, *, iostat=istat) v
1266 | else
1267 | write(tmp, fmt, iostat=istat) v
1268 | end if
1269 | if (istat/=0) then
1270 | write(error_unit,'(A)') 'Error in real_to_string'
1271 | str = '****'
1272 | else
1273 | str = trim(adjustl(tmp))
1274 | end if
1275 |
1276 | end subroutine real_to_string
1277 | !*****************************************************************************************
1278 |
1279 | !*****************************************************************************************
1280 | !> author: Jacob Williams
1281 | !
1282 | ! Real vector to string.
1283 |
1284 | subroutine vec_to_string(v, fmt, str, use_numpy, is_tuple)
1285 |
1286 | real(wp), dimension(:), intent(in) :: v !! real values
1287 | character(len=*), intent(in) :: fmt !! real format string
1288 | character(len=:), allocatable, intent(out) :: str !! real values stringified
1289 | logical, intent(in) :: use_numpy !! activate numpy python module usage
1290 | logical,intent(in),optional :: is_tuple !! if true [default], use '()', if false use '[]'
1291 |
1292 | integer :: i !! counter
1293 | integer :: istat !! IO status
1294 | character(len=max_real_len) :: tmp !! dummy string
1295 | logical :: tuple
1296 |
1297 | if (present(is_tuple)) then
1298 | tuple = is_tuple
1299 | else
1300 | tuple = .false.
1301 | end if
1302 |
1303 | if (tuple) then
1304 | str = '('
1305 | else
1306 | str = '['
1307 | end if
1308 |
1309 | do i=1, size(v)
1310 | if (fmt=='*') then
1311 | write(tmp, *, iostat=istat) v(i)
1312 | else
1313 | write(tmp, fmt, iostat=istat) v(i)
1314 | end if
1315 | if (istat/=0) then
1316 | write(error_unit,'(A)') 'Error in vec_to_string'
1317 | str = '****'
1318 | return
1319 | end if
1320 | str = str//trim(adjustl(tmp))
1321 | if (i author: Jacob Williams
1338 | !
1339 | ! Real matrix (rank 2) to string.
1340 |
1341 | subroutine matrix_to_string(v, fmt, str, use_numpy)
1342 |
1343 | real(wp), dimension(:,:), intent(in) :: v !! real values
1344 | character(len=*), intent(in) :: fmt !! real format string
1345 | character(len=:), allocatable, intent(out) :: str !! real values stringified
1346 | logical, intent(in) :: use_numpy !! activate numpy python module usage
1347 |
1348 | integer :: i !! counter
1349 | character(len=:),allocatable :: tmp !! dummy string
1350 |
1351 | str = '['
1352 | do i=1, size(v,1) !rows
1353 | call vec_to_string(v(i,:), fmt, tmp, use_numpy) !one row at a time
1354 | str = str//trim(adjustl(tmp))
1355 | if (i author: Jacob Williams
1367 | ! date: 8/16/2015
1368 | !
1369 | ! Write the buffer to a file, and then execute it with Python.
1370 | !
1371 | ! If user specifies a Python file name, then the file is kept, otherwise
1372 | ! a temporary filename is used, and the file is deleted after it is used.
1373 |
1374 | subroutine execute(me, pyfile, istat, python)
1375 |
1376 | class(pyplot), intent(inout) :: me !! pytplot handler
1377 | character(len=*), intent(in), optional :: pyfile !! name of the python script to generate
1378 | integer, intent (out),optional :: istat !! status output (0 means no problems)
1379 | character(len=*), intent(in),optional :: python !! python executable to use. (by default, this is 'python')
1380 |
1381 | integer :: iunit !! IO unit
1382 | character(len=:), allocatable :: file !! file name
1383 | logical :: scratch !! if a scratch file is to be used
1384 | integer :: iostat !! open/close status code
1385 | character(len=:), allocatable :: python_ !! python executable to use
1386 |
1387 | if (allocated(me%str)) then
1388 |
1389 | if (present(istat)) istat = 0
1390 |
1391 | scratch = (.not. present(pyfile))
1392 |
1393 | !file name to use:
1394 | if (scratch) then
1395 | file = trim(tmp_file) !use the default
1396 | else
1397 | file = trim(pyfile) !use the user-specified name
1398 | end if
1399 |
1400 | if (file == '') then
1401 | if (present(istat)) istat = -1
1402 | write(error_unit,'(A)') 'Error: filename is blank.'
1403 | return
1404 | end if
1405 |
1406 | !open the file:
1407 | open(newunit=iunit, file=file, status='REPLACE', iostat=iostat)
1408 | if (iostat/=0) then
1409 | if (present(istat)) istat = iostat
1410 | write(error_unit,'(A)') 'Error opening file: '//trim(file)
1411 | return
1412 | end if
1413 |
1414 | !write to the file:
1415 | write(iunit, '(A)') me%str
1416 |
1417 | !to ensure that the file is there for the next
1418 | !command line call, we have to close it here.
1419 | close(iunit, iostat=iostat)
1420 | if (iostat/=0) then
1421 | if (present(istat)) istat = iostat
1422 | write(error_unit,'(A)') 'Error closing file: '//trim(file)
1423 | else
1424 |
1425 | if (present(python)) then
1426 | python_ = trim(python)
1427 | else
1428 | python_ = python_exe
1429 | end if
1430 |
1431 | !run the file using python:
1432 | if (file(1:1)/='"') then
1433 | ! if not already in quotes, should enclose in quotes
1434 | call execute_command_line(python_//' "'//file//'"')
1435 | else
1436 | call execute_command_line(python_//' '//file)
1437 | end if
1438 |
1439 | if (scratch) then
1440 | !delete the file (have to reopen it because
1441 | !Fortran has no file delete function)
1442 | open(newunit=iunit, file=file, status='OLD', iostat=iostat)
1443 | if (iostat==0) close(iunit, status='DELETE', iostat=iostat)
1444 | end if
1445 | if (iostat/=0) then
1446 | if (present(istat)) istat = iostat
1447 | write(error_unit,'(A)') 'Error closing file.'
1448 | end if
1449 |
1450 | end if
1451 |
1452 | !cleanup:
1453 | if (allocated(file)) deallocate(file)
1454 |
1455 | else
1456 | if (present(istat)) istat = -1
1457 | end if
1458 |
1459 | end subroutine execute
1460 | !*****************************************************************************************
1461 |
1462 | !*****************************************************************************************
1463 | !> author: Jacob Williams
1464 | !
1465 | ! Some final things to add before saving or showing the figure.
1466 |
1467 | subroutine finish_ops(me)
1468 |
1469 | class(pyplot),intent(inout) :: me !! pyplot handler
1470 |
1471 | if (me%show_legend) then
1472 | call me%add_str('ax.legend(loc="best")')
1473 | call me%add_str('')
1474 | end if
1475 | if (me%axis_equal) then
1476 | if (me%mplot3d) then
1477 | call me%add_str('ax.set_aspect("auto")')
1478 | call me%add_str('')
1479 |
1480 | call me%add_str('def set_axes_equal(ax):')
1481 | call me%add_str(' x_limits = ax.get_xlim3d()')
1482 | call me%add_str(' y_limits = ax.get_ylim3d()')
1483 | call me%add_str(' z_limits = ax.get_zlim3d()')
1484 | call me%add_str(' x_range = abs(x_limits[1] - x_limits[0])')
1485 | call me%add_str(' x_middle = np.mean(x_limits)')
1486 | call me%add_str(' y_range = abs(y_limits[1] - y_limits[0])')
1487 | call me%add_str(' y_middle = np.mean(y_limits)')
1488 | call me%add_str(' z_range = abs(z_limits[1] - z_limits[0])')
1489 | call me%add_str(' z_middle = np.mean(z_limits)')
1490 | call me%add_str(' plot_radius = 0.5*max([x_range, y_range, z_range])')
1491 | call me%add_str(' ax.set_xlim3d([x_middle - plot_radius, x_middle + plot_radius])')
1492 | call me%add_str(' ax.set_ylim3d([y_middle - plot_radius, y_middle + plot_radius])')
1493 | call me%add_str(' ax.set_zlim3d([z_middle - plot_radius, z_middle + plot_radius])')
1494 | call me%add_str('set_axes_equal(ax)')
1495 |
1496 | else
1497 | call me%add_str('ax.axis("equal")')
1498 | end if
1499 | call me%add_str('')
1500 | end if
1501 | if (allocated(me%xaxis_date_fmt) .or. allocated(me%yaxis_date_fmt)) then
1502 | call me%add_str('from matplotlib.dates import DateFormatter')
1503 | if (allocated(me%xaxis_date_fmt)) &
1504 | call me%add_str('ax.xaxis.set_major_formatter(DateFormatter("'//trim(me%xaxis_date_fmt)//'"))')
1505 | if (allocated(me%yaxis_date_fmt)) &
1506 | call me%add_str('ax.yaxis.set_major_formatter(DateFormatter("'//trim(me%yaxis_date_fmt)//'"))')
1507 | call me%add_str('')
1508 | end if
1509 | if (me%tight_layout) then
1510 | call me%add_str('fig.tight_layout()')
1511 | call me%add_str('')
1512 | end if
1513 |
1514 | end subroutine finish_ops
1515 | !*****************************************************************************************
1516 |
1517 | !*****************************************************************************************
1518 | !> author: Jacob Williams
1519 | !
1520 | ! Save the figure.
1521 | !
1522 | !### History
1523 | ! * modified: Johannes Rieke 6/16/2017
1524 | ! * modified: Jacob Williams 6/16/2017
1525 |
1526 | subroutine savefig(me, figfile, pyfile, dpi, transparent, facecolor, edgecolor, orientation, istat, python)
1527 |
1528 | class(pyplot), intent(inout) :: me !! pyplot handler
1529 | character(len=*), intent(in) :: figfile !! file name for the figure
1530 | character(len=*), intent(in), optional :: pyfile !! name of the Python script to generate
1531 | character(len=*), intent(in), optional :: dpi !! resolution of the figure for png
1532 | !! [note this is a string]
1533 | logical, intent(in), optional :: transparent !! transparent background (T/F)
1534 | character(len=*), intent(in), optional :: facecolor !! the colors of the figure rectangle
1535 | character(len=*), intent(in), optional :: edgecolor !! the colors of the figure rectangle
1536 | character(len=*), intent(in), optional :: orientation !! 'landscape' or 'portrait'
1537 | integer, intent (out), optional :: istat !! status output (0 means no problems)
1538 | character(len=*), intent(in),optional :: python !! python executable to use. (by default, this is 'python')
1539 |
1540 | character(len=:),allocatable :: tmp !! for building the `savefig` arguments.
1541 |
1542 | if (allocated(me%str)) then
1543 |
1544 | if (present(istat)) istat = 0
1545 |
1546 | !finish up the string:
1547 | call me%finish_ops()
1548 |
1549 | !build the savefig arguments:
1550 | tmp = trim(me%raw_str_token)//'"'//trim(figfile)//'"'
1551 | if (present(dpi)) tmp = tmp//', dpi='//trim(dpi)
1552 | if (present(transparent)) then
1553 | if (transparent) then
1554 | tmp = tmp//', transparent=True'
1555 | else
1556 | tmp = tmp//', transparent=False'
1557 | end if
1558 | end if
1559 | if (present(facecolor)) tmp = tmp//', facecolor="'//trim(facecolor)//'"'
1560 | if (present(edgecolor)) tmp = tmp//', edgecolor="'//trim(edgecolor)//'"'
1561 | if (present(orientation)) tmp = tmp//', orientation="'//trim(orientation)//'"'
1562 | if (me%use_oo_api) then
1563 | call me%add_str('canvas = FigureCanvas(fig)')
1564 | call me%add_str('canvas.print_figure('//tmp//')')
1565 | else
1566 | call me%add_str('plt.savefig('//tmp//')')
1567 | endif
1568 | deallocate(tmp)
1569 |
1570 | !run it:
1571 | call me%execute(pyfile, istat=istat, python=python)
1572 |
1573 | else
1574 | if (present(istat)) istat = -1
1575 | write(error_unit,'(A)') 'error in savefig: pyplot class not properly initialized.'
1576 | end if
1577 |
1578 | end subroutine savefig
1579 | !*****************************************************************************************
1580 |
1581 | !*****************************************************************************************
1582 | !> author: Johannes Rieke
1583 | ! date: 6/16/2017
1584 | !
1585 | ! Shows the figure.
1586 |
1587 | subroutine showfig(me, pyfile, istat, python)
1588 |
1589 | class(pyplot), intent(inout) :: me !! pyplot handler
1590 | character(len=*), intent(in), optional :: pyfile !! name of the Python script to generate
1591 | integer, intent (out), optional :: istat !! status output (0 means no problems)
1592 | character(len=*), intent(in),optional :: python !! python executable to use. (by default, this is 'python')
1593 |
1594 | if (.not. allocated(me%str)) then
1595 |
1596 | if (present(istat)) istat = -1
1597 | write(error_unit,'(A)') 'error in showfig: pyplot class not properly initialized.'
1598 |
1599 | else if (me%use_oo_api) then
1600 |
1601 | if (present(istat)) istat = -2
1602 | write(error_unit,'(A)') 'error in showfig: not compatible with "use_oo_api" option'
1603 |
1604 | else
1605 |
1606 | if (present(istat)) istat = 0
1607 |
1608 | !finish up the string:
1609 | call me%finish_ops()
1610 |
1611 | !show figure:
1612 | call me%add_str('plt.show()')
1613 |
1614 | !run it:
1615 | call me%execute(pyfile, istat=istat, python=python)
1616 |
1617 | end if
1618 |
1619 | end subroutine showfig
1620 | !*****************************************************************************************
1621 |
1622 | !*****************************************************************************************
1623 | end module pyplot_module
1624 | !*****************************************************************************************
1625 |
--------------------------------------------------------------------------------
/test/color_test.f90:
--------------------------------------------------------------------------------
1 | !*****************************************************************************************
2 | !>
3 | ! Color test
4 |
5 | program color_test
6 |
7 | use pyplot_module, only : pyplot, wp => pyplot_wp
8 |
9 | implicit none
10 |
11 | type(pyplot) :: plt !! pytplot handler
12 | integer :: istat
13 | real(wp), parameter :: F(3) = [0.4510d0, 0.3098d0, 0.5882d0] ! Fortran-lang color
14 | real(wp), parameter :: Y(3) = [0.9608d0, 0.8157d0, 0.0118d0] ! Yellow
15 |
16 | real(wp),dimension(3),parameter :: Ax = [1,2,3]
17 | real(wp),dimension(3),parameter :: Ay = [1,2,3]
18 | real(wp),dimension(3),parameter :: Bx = [1,2,3]
19 | real(wp),dimension(3),parameter :: By = [4,5,6]
20 |
21 | character(len=*), parameter :: testdir = "test/"
22 |
23 | call plt%initialize(figsize=[20,10],title='color test')
24 |
25 | call plt%add_plot(Ax,Ay,label='',linestyle='o',markersize=5,color=F)
26 | call plt%add_plot(Bx,By,label='',linestyle='o',markersize=5,color=Y)
27 |
28 | call plt%savefig(testdir//'color_test.png',&
29 | pyfile=testdir//'color_test.py',istat=istat)
30 |
31 | end program color_test
32 | !*****************************************************************************************
33 |
--------------------------------------------------------------------------------
/test/date_test.f90:
--------------------------------------------------------------------------------
1 | !*****************************************************************************************
2 | !>
3 | ! Unit test for [[pyplot_module]]. Using the `xaxis_date_fmt` option for x-axis dates.
4 |
5 | program date_test
6 |
7 | use pyplot_module, only : pyplot, wp => pyplot_wp
8 |
9 | implicit none
10 |
11 | integer,parameter :: n = 100
12 |
13 | real(wp), dimension(:),allocatable :: x !! x values
14 | real(wp), dimension(:),allocatable :: y !! y values
15 | real(wp), dimension(:),allocatable :: sx !! sin(x) values
16 | real(wp), dimension(:),allocatable :: cx !! cos(x) values
17 | real(wp), dimension(:),allocatable :: tx !! sin(x)*cos(x) values
18 | type(pyplot) :: plt !! pytplot handler
19 | integer :: i !! counter
20 | integer :: istat !! status code
21 |
22 | character(len=*), parameter :: testdir = "test/"
23 | character(len=*), parameter :: xaxis_date_fmt = '%m/%d/%y %H:%M:%S'
24 | character(len=*), parameter :: yaxis_date_fmt = '%H:%M:%S'
25 |
26 | ! size arrays:
27 | allocate(x(n))
28 | allocate(sx(n))
29 | allocate(cx(n))
30 | allocate(tx(n))
31 |
32 | !generate some data:
33 | x = [(real(i,wp), i=0,size(x)-1)]/5.0_wp
34 | sx = 10*sin(x)
35 | cx = cos(x)
36 | tx = sx * cx
37 |
38 | !2d line plot:
39 | call plt%initialize(grid=.true.,xlabel='Calendar date',figsize=[20,10],&
40 | title='date test',legend=.true.,axis_equal=.true.,&
41 | tight_layout=.true., &
42 | xaxis_date_fmt=xaxis_date_fmt, yaxis_date_fmt=yaxis_date_fmt)
43 | call plt%add_plot(x,sx,label='$\sin (x)$',linestyle='b-o',markersize=5,linewidth=2,istat=istat)
44 | call plt%add_plot(x,cx,label='$\cos (x)$',linestyle='r-o',markersize=5,linewidth=2,istat=istat)
45 | call plt%add_plot(x,tx,label='$\sin (x) \cos (x)$',linestyle='g-o',markersize=2,linewidth=1,istat=istat)
46 | call plt%savefig(testdir//'datetest.png', pyfile=testdir//'datetest.py',&
47 | istat=istat)
48 |
49 | end program date_test
50 | !*****************************************************************************************
51 |
--------------------------------------------------------------------------------
/test/test.f90:
--------------------------------------------------------------------------------
1 | !*****************************************************************************************
2 | !> author: Jacob Williams
3 | ! date: 4/14/2015
4 | ! license: BSD
5 | !
6 | ! Unit test for [[pyplot_module]].
7 |
8 | program test
9 |
10 | use pyplot_module, only : pyplot, wp => pyplot_wp
11 |
12 | implicit none
13 |
14 | integer,parameter :: n = 100
15 |
16 | real(wp), dimension(:),allocatable :: x !! x values
17 | real(wp), dimension(:),allocatable :: y !! y values
18 | real(wp), dimension(:),allocatable :: xerr !! error values
19 | real(wp), dimension(:),allocatable :: yerr !! error values for bar chart
20 | real(wp), dimension(:),allocatable :: sx !! sin(x) values
21 | real(wp), dimension(:),allocatable :: cx !! cos(x) values
22 | real(wp), dimension(:),allocatable :: zx !!
23 | real(wp), dimension(:),allocatable :: tx !! sin(x)*cos(x) values
24 | real(wp), dimension(:,:),allocatable :: z !! z matrix for contour plot
25 | real(wp), dimension(:,:),allocatable :: mat !! image values
26 | type(pyplot) :: plt !! pytplot handler
27 | integer :: i !! counter
28 | integer :: j !! counter
29 | real(wp) :: r2 !! temp variable
30 | integer :: istat !! status code
31 |
32 | real(wp),parameter :: pi = acos(-1.0_wp)
33 | real(wp),parameter :: deg2rad = pi/180.0_wp
34 |
35 | character(len=*), parameter :: testdir = "test/"
36 |
37 | ! size arrays:
38 | allocate(x(n))
39 | allocate(y(n))
40 | allocate(yerr(n))
41 | allocate(sx(n))
42 | allocate(cx(n))
43 | allocate(zx(n))
44 | allocate(tx(n))
45 | allocate(z(n,n))
46 | allocate(mat(n,n))
47 |
48 | !generate some data:
49 | x = [(real(i,wp), i=0,size(x)-1)]/5.0_wp
50 | sx = sin(x)
51 | cx = cos(x)
52 | tx = sx * cx
53 | zx = 0.0_wp
54 | yerr = abs(sx*.25_wp)
55 |
56 | do i=1,n
57 | do j=1,n
58 | mat(i,j) = sin(real(i,wp)*real(j,wp))
59 | end do
60 | end do
61 |
62 | !2d line plot:
63 | call plt%initialize(grid=.true.,xlabel='angle (rad)',figsize=[20,10],&
64 | title='plot test',legend=.true.,axis_equal=.true.,&
65 | tight_layout=.true.)
66 | call plt%add_plot(x,sx,label='$\sin (x)$',linestyle='b-o',markersize=5,linewidth=2,istat=istat)
67 | call plt%add_plot(x,cx,label='$\cos (x)$',linestyle='r-o',markersize=5,linewidth=2,istat=istat)
68 | call plt%add_plot(x,tx,label='$\sin (x) \cos (x)$',linestyle='g-o',markersize=2,linewidth=1,istat=istat)
69 | call plt%savefig(testdir//'plottest.png', pyfile=testdir//'plottest.py',&
70 | istat=istat)
71 |
72 | !bar chart:
73 | tx = 0.1_wp !for bar width
74 | call plt%initialize(grid=.true.,xlabel='angle (rad)',&
75 | title='bar test',legend=.true.,figsize=[20,10],&
76 | font_size = 20,&
77 | axes_labelsize = 20,&
78 | xtick_labelsize = 20,&
79 | ytick_labelsize = 20,&
80 | legend_fontsize = 20, raw_strings=.true. )
81 | call plt%add_bar(x=x,height=sx,width=tx,label='$\sin (x)$',&
82 | color='r',yerr=yerr,xlim=[0.0_wp, 20.0_wp],align='center',istat=istat)
83 | call plt%savefig(testdir//'bartest.png', pyfile=testdir//'bartest.py',&
84 | istat=istat)
85 |
86 | !contour plot:
87 | x = [(real(i,wp), i=0,n-1)]/100.0_wp
88 | y = [(real(i,wp), i=0,n-1)]/100.0_wp
89 | do i=1,n
90 | do j=1,n
91 | r2 = x(i)**2 + y(j)**2
92 | z(i,j) = sin(x(i))*cos(y(j))*sin(r2)/(1.0_wp+log(r2+1.0_wp))
93 | end do
94 | end do
95 | call plt%initialize(grid=.true.,xlabel='x angle (rad)',&
96 | ylabel='y angle (rad)',figsize=[10,10],&
97 | title='Contour plot test', real_fmt='*',&
98 | axisbelow=.false.)
99 | call plt%add_contour(x, y, z, linestyle='-', &
100 | filled=.true., cmap='bone', colorbar=.true.,&
101 | istat=istat)
102 | call plt%savefig(testdir//'contour.png',pyfile=testdir//'contour.py',istat=istat)
103 |
104 | !image plot:
105 | call plt%initialize(grid=.true.,xlabel='x',ylabel='y',figsize=[20,20],&
106 | title='imshow test',&
107 | real_fmt='(F9.3)')
108 | call plt%add_imshow(mat,xlim=[0.0_wp, 100.0_wp],ylim=[0.0_wp, 100.0_wp],istat=istat)
109 | call plt%savefig(testdir//'imshow.png', pyfile=testdir//'imshow.py',&
110 | istat=istat)
111 |
112 | !wireframe plot:
113 | call plt%initialize(grid=.true.,xlabel='x angle (rad)',&
114 | ylabel='y angle (rad)',figsize=[10,10],&
115 | title='Wireframe plot test', real_fmt='*',&
116 | axisbelow=.false.,mplot3d=.true.,use_numpy=.true.)
117 | call plt%plot_wireframe(x, y, z, label='', linestyle='-', &
118 | cmap='bone', colorbar=.true.,&
119 | istat=istat)
120 | call plt%savefig(testdir//'wireframe.png', pyfile=testdir//'wireframe.py',&
121 | istat=istat)
122 |
123 | !histogram chart:
124 | x = [0.194,0.501,-1.241,1.425,-2.217,-0.342,-0.979,0.909,0.994,0.101, &
125 | -0.131,-0.627,0.463,1.404,0.036,-2.000,0.109,1.250,-1.035,-1.115, &
126 | 0.935,0.496,1.100,0.770,-1.307,-0.693,-0.072,-1.331,-0.701, &
127 | -0.494,0.666,-0.313,-0.430,-0.654,1.638,-0.334,-0.418,0.550,-0.034, &
128 | 0.473,0.704,0.801,-0.157,0.055,-0.057,-1.049,-1.022,0.495,0.756, &
129 | 0.149,0.543,-0.813,-0.171,-0.994,-1.532,0.502,1.324,-0.593,-0.467, &
130 | 0.372,-0.904,1.255,0.931,-0.779,1.529,-0.036,0.783,0.292,-0.792, &
131 | -0.223,-0.325,0.225,-0.492,-0.941,0.065,1.300,-1.241,-1.124,-0.499, &
132 | 1.233,-0.845,-0.948,-1.060,1.103,-1.154,-0.594,0.335,-1.423,0.571, &
133 | -0.903,1.129,-0.372,-1.043,-1.327,0.147,1.056,1.068,-0.699,0.988,-0.630]
134 |
135 | call plt%initialize(grid=.true.,xlabel='x',&
136 | title='hist test',&
137 | legend=.true.,figsize=[20,10],&
138 | font_size = 20,&
139 | axes_labelsize = 20,&
140 | xtick_labelsize = 20,&
141 | ytick_labelsize = 20,&
142 | legend_fontsize = 20 )
143 |
144 | call plt%add_hist(x=x, label='x',istat=istat)
145 | call plt%savefig(testdir//'histtest1.png', pyfile=testdir//'histtest1.py',&
146 | istat=istat)
147 |
148 | call plt%initialize(grid=.true.,xlabel='x',&
149 | title='cumulative hist test',&
150 | legend=.true.,figsize=[20,10],&
151 | font_size = 20,&
152 | axes_labelsize = 20,&
153 | xtick_labelsize = 20,&
154 | ytick_labelsize = 20,&
155 | legend_fontsize = 20 )
156 |
157 | call plt%add_hist(x=x, label='x', bins=8, cumulative=.true.,istat=istat)
158 | call plt%savefig(testdir//'histtest2.png', &
159 | pyfile=testdir//'histtest2.py', &
160 | dpi='200', &
161 | transparent=.true.,istat=istat)
162 |
163 | !3D plot:
164 | call plt%initialize(grid=.true.,&
165 | xlabel='x (km)',ylabel='y (km)',zlabel='z (km)',&
166 | title='Orbit',&
167 | axis_equal=.true.,&
168 | mplot3d=.true.,&
169 | figsize=[20,10] )
170 |
171 | x = [(real(i,wp), i=0,size(x)-1)]/5.0_wp
172 | sx = 7000.0_wp * cos(x * deg2rad)
173 | cx = 7000.0_wp * sin(x * deg2rad)
174 | zx = 0.0_wp
175 | call plt%add_3d_plot(sx,cx,zx,&
176 | label='orbit',linestyle='r-',&
177 | linewidth=2,istat=istat)
178 | call plt%add_sphere(6378.0_wp,0.0_wp,0.0_wp,0.0_wp,&
179 | color='Blue',n_facets=500,&
180 | antialiased=.true.,istat=istat)
181 | call plt%savefig(testdir//'orbit.png', &
182 | pyfile=testdir//'orbit.py', &
183 | dpi='200', &
184 | transparent=.true.,istat=istat)
185 |
186 | ! Errorbar plot:
187 | call plt%initialize(grid=.true.,&
188 | xlabel='x',ylabel='y',&
189 | title='Errorbar Plot Example',&
190 | figsize=[20,10] )
191 |
192 | x = [(real(i,wp), i=0, 360, 10)]
193 | y = 10.0_wp * cos(x * deg2rad)
194 | xerr = abs(sin(x * deg2rad) * 5.0_wp)
195 | yerr = abs(sin(y * deg2rad) * 10.0_wp)
196 |
197 | call plt%add_errorbar(x, y, label='y', linestyle='.', &
198 | xerr=xerr, yerr=yerr, istat=istat)
199 | call plt%savefig(testdir//'errorbar.png', &
200 | pyfile=testdir//'errorbar.py', &
201 | dpi='200', &
202 | transparent=.true.,istat=istat, python='python')
203 |
204 | ! also test one with spaces and () in the filename
205 | call plt%savefig(testdir//'error bar (1).png', &
206 | pyfile=testdir//'error bar (1).py', &
207 | dpi='200', &
208 | transparent=.true.,istat=istat, python='python')
209 |
210 | end program test
211 | !*****************************************************************************************
212 |
--------------------------------------------------------------------------------