@@ -29,31 +29,32 @@ module pyplot_module
29
29
integer , parameter :: max_real_len = 30 ! ! max string length for reals
30
30
31
31
type, public :: pyplot
32
-
32
+
33
33
! ! The main pyplot class.
34
-
34
+
35
35
private
36
36
37
37
character (len= :), allocatable :: str ! ! string buffer
38
38
39
39
logical :: show_legend = .false. ! ! show legend into plot
40
40
logical :: use_numpy = .true. ! ! use numpy python module
41
41
logical :: mplot3d = .false. ! ! it is a 3d plot
42
-
42
+ logical :: axis_equal = .false. ! ! equal scale on each axis
43
+
43
44
contains
44
-
45
+
45
46
! public methods
46
47
procedure , public :: initialize ! ! initialize pyplot instance
47
48
procedure , public :: add_plot ! ! add a 2d plot to pyplot instance
48
49
procedure , public :: add_3d_plot ! ! add a 3d plot to pyplot instance
49
50
procedure , public :: add_bar ! ! add a barplot to pyplot instance
50
51
procedure , public :: savefig ! ! save plots of pyplot instance
51
52
procedure , public :: destroy ! ! destroy pyplot instance
52
-
53
+
53
54
! private methods
54
55
procedure :: execute ! ! execute pyplot commands
55
56
procedure :: add_str ! ! add string to pytplot instance buffer
56
-
57
+
57
58
end type pyplot
58
59
59
60
contains
@@ -65,11 +66,11 @@ module pyplot_module
65
66
! Destructor.
66
67
67
68
subroutine destroy (me )
68
-
69
+
69
70
class(pyplot),intent (inout ) :: me ! ! pyplot handler
70
71
71
72
if (allocated (me% str)) deallocate (me% str)
72
-
73
+
73
74
end subroutine destroy
74
75
! *****************************************************************************************
75
76
@@ -79,12 +80,12 @@ end subroutine destroy
79
80
! Add a string to the buffer.
80
81
81
82
subroutine add_str (me ,str )
82
-
83
+
83
84
class(pyplot), intent (inout ) :: me ! ! pyplot handler
84
85
character (len=* ), intent (in ) :: str ! ! str to be added to pyplot handler buffer
85
86
86
87
me% str = me% str// str// new_line(' ' )
87
-
88
+
88
89
end subroutine add_str
89
90
! *****************************************************************************************
90
91
@@ -95,8 +96,8 @@ end subroutine add_str
95
96
96
97
subroutine initialize (me , grid , xlabel , ylabel , zlabel , title , legend , use_numpy , figsize , &
97
98
font_size , axes_labelsize , xtick_labelsize , ytick_labelsize , ztick_labelsize , &
98
- legend_fontsize , mplot3d )
99
-
99
+ legend_fontsize , mplot3d , axis_equal )
100
+
100
101
class(pyplot), intent (inout ) :: me ! ! pyplot handler
101
102
logical , intent (in ), optional :: grid ! ! activate grid drawing
102
103
character (len=* ), intent (in ), optional :: xlabel ! ! label of x axis
@@ -113,7 +114,8 @@ subroutine initialize(me, grid, xlabel, ylabel, zlabel, title, legend, use_numpy
113
114
integer , intent (in ), optional :: ztick_labelsize ! ! size of z axis tick lables
114
115
integer , intent (in ), optional :: legend_fontsize ! ! size of legend font
115
116
logical , intent (in ), optional :: mplot3d ! ! set true for 3d plots
116
-
117
+ logical , intent (in ), optional :: axis_equal ! ! set true for axis = 'equal'
118
+
117
119
character (len= max_int_len) :: width_str ! ! figure width dummy string
118
120
character (len= max_int_len) :: height_str ! ! figure height dummy string
119
121
character (len= max_int_len) :: font_size_str ! ! font size dummy string
@@ -145,6 +147,11 @@ subroutine initialize(me, grid, xlabel, ylabel, zlabel, title, legend, use_numpy
145
147
else
146
148
me% mplot3d = .false.
147
149
end if
150
+ if (present (axis_equal)) then
151
+ me% axis_equal = axis_equal
152
+ else
153
+ me% axis_equal = .false.
154
+ end if
148
155
149
156
call optional_int_to_string(font_size, font_size_str, default_font_size_str)
150
157
call optional_int_to_string(axes_labelsize, axes_labelsize_str, default_font_size_str)
@@ -178,13 +185,13 @@ subroutine initialize(me, grid, xlabel, ylabel, zlabel, title, legend, use_numpy
178
185
else
179
186
call me% add_str(' fig = plt.figure()' )
180
187
end if
181
-
188
+
182
189
if (me% mplot3d) then
183
190
call me% add_str(' ax = fig.gca(projection='' 3d'' )' )
184
191
else
185
192
call me% add_str(' ax = fig.gca()' )
186
193
end if
187
-
194
+
188
195
if (present (grid)) then
189
196
if (grid) call me% add_str(' ax.grid()' )
190
197
end if
@@ -193,9 +200,9 @@ subroutine initialize(me, grid, xlabel, ylabel, zlabel, title, legend, use_numpy
193
200
if (present (ylabel)) call me% add_str(' ax.set_ylabel("' // trim (ylabel)// ' ")' )
194
201
if (present (zlabel)) call me% add_str(' ax.set_zlabel("' // trim (zlabel)// ' ")' )
195
202
if (present (title)) call me% add_str(' ax.set_title("' // trim (title) // ' ")' )
196
-
203
+
197
204
call me% add_str(' ' )
198
-
205
+
199
206
end subroutine initialize
200
207
! *****************************************************************************************
201
208
@@ -205,15 +212,15 @@ end subroutine initialize
205
212
! Add an x,y plot.
206
213
207
214
subroutine add_plot (me , x , y , label , linestyle , markersize , linewidth )
208
-
215
+
209
216
class(pyplot), intent (inout ) :: me ! ! pyplot handler
210
217
real (wp), dimension (:), intent (in ) :: x ! ! x values
211
218
real (wp), dimension (:), intent (in ) :: y ! ! y values
212
219
character (len=* ), intent (in ) :: label ! ! plot label
213
220
character (len=* ), intent (in ) :: linestyle ! ! style of the plot line
214
221
integer , intent (in ), optional :: markersize ! ! size of the plot markers
215
222
integer , intent (in ), optional :: linewidth ! ! width of the plot line
216
-
223
+
217
224
character (len= :), allocatable :: xstr ! ! x values strinfied
218
225
character (len= :), allocatable :: ystr ! ! y values strinfied
219
226
character (len= max_int_len) :: imark ! ! actual markers size
@@ -249,7 +256,7 @@ subroutine add_plot(me, x, y, label, linestyle, markersize, linewidth)
249
256
else
250
257
error stop ' Error in add_plot: pyplot class not properly initialized.'
251
258
end if
252
-
259
+
253
260
end subroutine add_plot
254
261
! *****************************************************************************************
255
262
@@ -261,7 +268,7 @@ end subroutine add_plot
261
268
! @note Must initialize the class with ```mplot3d=.true.```
262
269
263
270
subroutine add_3d_plot (me , x , y , z , label , linestyle , markersize , linewidth )
264
-
271
+
265
272
class(pyplot), intent (inout ) :: me ! ! pyplot handler
266
273
real (wp), dimension (:), intent (in ) :: x ! ! x values
267
274
real (wp), dimension (:), intent (in ) :: y ! ! y values
@@ -270,7 +277,7 @@ subroutine add_3d_plot(me, x, y, z, label, linestyle, markersize, linewidth)
270
277
character (len=* ), intent (in ) :: linestyle ! ! style of the plot line
271
278
integer , intent (in ), optional :: markersize ! ! size of the plot markers
272
279
integer , intent (in ), optional :: linewidth ! ! width of the plot line
273
-
280
+
274
281
character (len= :), allocatable :: xstr ! ! x values strinfied
275
282
character (len= :), allocatable :: ystr ! ! y values strinfied
276
283
character (len= :), allocatable :: zstr ! ! z values strinfied
@@ -311,15 +318,15 @@ subroutine add_3d_plot(me, x, y, z, label, linestyle, markersize, linewidth)
311
318
else
312
319
error stop ' Error in add_3d_plot: pyplot class not properly initialized.'
313
320
end if
314
-
321
+
315
322
end subroutine add_3d_plot
316
323
! *****************************************************************************************
317
324
318
325
! *****************************************************************************************
319
326
! > author: Jacob Williams
320
327
!
321
328
! Add a bar plot.
322
-
329
+
323
330
subroutine add_bar (me , left , height , label , width , bottom , color )
324
331
325
332
class(pyplot), intent (inout ) :: me ! ! pyplot handler
@@ -329,7 +336,7 @@ subroutine add_bar(me, left, height, label, width, bottom, color)
329
336
real (wp), dimension (:), intent (in ), optional :: width ! ! width values
330
337
real (wp), dimension (:), intent (in ), optional :: bottom ! ! bottom values
331
338
character (len=* ), intent (in ), optional :: color ! ! plot color
332
-
339
+
333
340
character (len= :), allocatable :: xstr ! ! x axis values stringified
334
341
character (len= :), allocatable :: ystr ! ! y axis values stringified
335
342
character (len= :), allocatable :: wstr ! ! width values stringified
@@ -382,7 +389,7 @@ end subroutine add_bar
382
389
! the optional argument is not present.
383
390
384
391
subroutine optional_int_to_string (int_value , string_value , default_value )
385
-
392
+
386
393
integer , intent (in ), optional :: int_value ! ! integer value
387
394
character (len=* ), intent (out ) :: string_value ! ! integer value stringified
388
395
character (len=* ), intent (in ) :: default_value ! ! default integer value
@@ -423,11 +430,11 @@ end subroutine integer_to_string
423
430
! Real vector to string.
424
431
425
432
subroutine vec_to_string (v , str , use_numpy )
426
-
433
+
427
434
real (wp), dimension (:), intent (in ) :: v ! ! real values
428
435
character (len= :), allocatable , intent (out ) :: str ! ! real values stringified
429
436
logical , intent (in ) :: use_numpy ! ! activate numpy python module usage
430
-
437
+
431
438
integer :: i ! ! counter
432
439
integer :: istat ! ! IO status
433
440
character (len= max_real_len) :: tmp ! ! dummy string
@@ -457,49 +464,49 @@ end subroutine vec_to_string
457
464
! a temporary filename is used, and the file is deleted after it is used.
458
465
459
466
subroutine execute (me , pyfile )
460
-
467
+
461
468
class(pyplot), intent (inout ) :: me ! ! pytplot handler
462
469
character (len=* ), intent (in ), optional :: pyfile ! ! name of the python script to generate
463
-
470
+
464
471
integer :: istat ! ! IO status
465
472
integer :: iunit ! ! IO unit
466
- character (len= :), allocatable :: file ! ! file name
473
+ character (len= :), allocatable :: file ! ! file name
467
474
logical :: scratch ! ! if a scratch file is to be used
468
475
469
476
if (allocated (me% str)) then
470
-
477
+
471
478
scratch = (.not. present (pyfile))
472
-
479
+
473
480
! file name to use:
474
481
if (scratch) then
475
482
file = trim (tmp_file) ! use the default
476
483
else
477
484
file = trim (pyfile) ! use the user-specified name
478
485
end if
479
-
486
+
480
487
! open the file:
481
488
open (newunit= iunit, file= file, status= ' REPLACE' , iostat= istat)
482
489
if (istat/= 0 ) error stop ' Error opening file.'
483
-
490
+
484
491
! write to the file:
485
492
write (iunit, ' (A)' ) me% str
486
493
487
494
! run the file using python:
488
495
call execute_command_line(python_exe// ' ' // file)
489
-
496
+
490
497
! close the file:
491
498
if (scratch) then
492
499
close (iunit, status= ' DELETE' , iostat= istat)
493
500
else
494
501
close (iunit, iostat= istat)
495
502
end if
496
503
if (istat/= 0 ) error stop ' Error closing file.'
497
-
504
+
498
505
! cleanup:
499
506
if (allocated (file)) deallocate (file)
500
507
501
508
end if
502
-
509
+
503
510
end subroutine execute
504
511
! *****************************************************************************************
505
512
@@ -509,7 +516,7 @@ end subroutine execute
509
516
! Save the figure.
510
517
511
518
subroutine savefig (me , figfile , pyfile )
512
-
519
+
513
520
class(pyplot), intent (inout ) :: me ! ! pyplot handler
514
521
character (len=* ), intent (in ) :: figfile ! ! file name for the figure
515
522
character (len=* ), intent (in ), optional :: pyfile ! ! name of the Python script to generate
@@ -521,6 +528,10 @@ subroutine savefig(me, figfile, pyfile)
521
528
call me% add_str(' ax.legend(loc="best")' )
522
529
call me% add_str(' ' )
523
530
end if
531
+ if (me% axis_equal) then
532
+ call me% add_str(' ax.axis("equal")' )
533
+ call me% add_str(' ' )
534
+ end if
524
535
call me% add_str(' plt.savefig("' // trim (figfile)// ' ")' )
525
536
526
537
! run it:
@@ -535,4 +546,4 @@ end subroutine savefig
535
546
536
547
! *****************************************************************************************
537
548
end module pyplot_module
538
- ! *****************************************************************************************
549
+ ! *****************************************************************************************
0 commit comments