@@ -29,31 +29,32 @@ module pyplot_module
2929 integer , parameter :: max_real_len = 30 ! ! max string length for reals
3030
3131 type, public :: pyplot
32-
32+
3333 ! ! The main pyplot class.
34-
34+
3535 private
3636
3737 character (len= :), allocatable :: str ! ! string buffer
3838
3939 logical :: show_legend = .false. ! ! show legend into plot
4040 logical :: use_numpy = .true. ! ! use numpy python module
4141 logical :: mplot3d = .false. ! ! it is a 3d plot
42-
42+ logical :: axis_equal = .false. ! ! equal scale on each axis
43+
4344 contains
44-
45+
4546 ! public methods
4647 procedure , public :: initialize ! ! initialize pyplot instance
4748 procedure , public :: add_plot ! ! add a 2d plot to pyplot instance
4849 procedure , public :: add_3d_plot ! ! add a 3d plot to pyplot instance
4950 procedure , public :: add_bar ! ! add a barplot to pyplot instance
5051 procedure , public :: savefig ! ! save plots of pyplot instance
5152 procedure , public :: destroy ! ! destroy pyplot instance
52-
53+
5354 ! private methods
5455 procedure :: execute ! ! execute pyplot commands
5556 procedure :: add_str ! ! add string to pytplot instance buffer
56-
57+
5758 end type pyplot
5859
5960 contains
@@ -65,11 +66,11 @@ module pyplot_module
6566! Destructor.
6667
6768 subroutine destroy (me )
68-
69+
6970 class(pyplot),intent (inout ) :: me ! ! pyplot handler
7071
7172 if (allocated (me% str)) deallocate (me% str)
72-
73+
7374 end subroutine destroy
7475! *****************************************************************************************
7576
@@ -79,12 +80,12 @@ end subroutine destroy
7980! Add a string to the buffer.
8081
8182 subroutine add_str (me ,str )
82-
83+
8384 class(pyplot), intent (inout ) :: me ! ! pyplot handler
8485 character (len=* ), intent (in ) :: str ! ! str to be added to pyplot handler buffer
8586
8687 me% str = me% str// str// new_line(' ' )
87-
88+
8889 end subroutine add_str
8990! *****************************************************************************************
9091
@@ -95,8 +96,8 @@ end subroutine add_str
9596
9697 subroutine initialize (me , grid , xlabel , ylabel , zlabel , title , legend , use_numpy , figsize , &
9798 font_size , axes_labelsize , xtick_labelsize , ytick_labelsize , ztick_labelsize , &
98- legend_fontsize , mplot3d )
99-
99+ legend_fontsize , mplot3d , axis_equal )
100+
100101 class(pyplot), intent (inout ) :: me ! ! pyplot handler
101102 logical , intent (in ), optional :: grid ! ! activate grid drawing
102103 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
113114 integer , intent (in ), optional :: ztick_labelsize ! ! size of z axis tick lables
114115 integer , intent (in ), optional :: legend_fontsize ! ! size of legend font
115116 logical , intent (in ), optional :: mplot3d ! ! set true for 3d plots
116-
117+ logical , intent (in ), optional :: axis_equal ! ! set true for axis = 'equal'
118+
117119 character (len= max_int_len) :: width_str ! ! figure width dummy string
118120 character (len= max_int_len) :: height_str ! ! figure height dummy string
119121 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
145147 else
146148 me% mplot3d = .false.
147149 end if
150+ if (present (axis_equal)) then
151+ me% axis_equal = axis_equal
152+ else
153+ me% axis_equal = .false.
154+ end if
148155
149156 call optional_int_to_string(font_size, font_size_str, default_font_size_str)
150157 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
178185 else
179186 call me% add_str(' fig = plt.figure()' )
180187 end if
181-
188+
182189 if (me% mplot3d) then
183190 call me% add_str(' ax = fig.gca(projection='' 3d'' )' )
184191 else
185192 call me% add_str(' ax = fig.gca()' )
186193 end if
187-
194+
188195 if (present (grid)) then
189196 if (grid) call me% add_str(' ax.grid()' )
190197 end if
@@ -193,9 +200,9 @@ subroutine initialize(me, grid, xlabel, ylabel, zlabel, title, legend, use_numpy
193200 if (present (ylabel)) call me% add_str(' ax.set_ylabel("' // trim (ylabel)// ' ")' )
194201 if (present (zlabel)) call me% add_str(' ax.set_zlabel("' // trim (zlabel)// ' ")' )
195202 if (present (title)) call me% add_str(' ax.set_title("' // trim (title) // ' ")' )
196-
203+
197204 call me% add_str(' ' )
198-
205+
199206 end subroutine initialize
200207! *****************************************************************************************
201208
@@ -205,15 +212,15 @@ end subroutine initialize
205212! Add an x,y plot.
206213
207214 subroutine add_plot (me , x , y , label , linestyle , markersize , linewidth )
208-
215+
209216 class(pyplot), intent (inout ) :: me ! ! pyplot handler
210217 real (wp), dimension (:), intent (in ) :: x ! ! x values
211218 real (wp), dimension (:), intent (in ) :: y ! ! y values
212219 character (len=* ), intent (in ) :: label ! ! plot label
213220 character (len=* ), intent (in ) :: linestyle ! ! style of the plot line
214221 integer , intent (in ), optional :: markersize ! ! size of the plot markers
215222 integer , intent (in ), optional :: linewidth ! ! width of the plot line
216-
223+
217224 character (len= :), allocatable :: xstr ! ! x values strinfied
218225 character (len= :), allocatable :: ystr ! ! y values strinfied
219226 character (len= max_int_len) :: imark ! ! actual markers size
@@ -249,7 +256,7 @@ subroutine add_plot(me, x, y, label, linestyle, markersize, linewidth)
249256 else
250257 error stop ' Error in add_plot: pyplot class not properly initialized.'
251258 end if
252-
259+
253260 end subroutine add_plot
254261! *****************************************************************************************
255262
@@ -261,7 +268,7 @@ end subroutine add_plot
261268! @note Must initialize the class with ```mplot3d=.true.```
262269
263270 subroutine add_3d_plot (me , x , y , z , label , linestyle , markersize , linewidth )
264-
271+
265272 class(pyplot), intent (inout ) :: me ! ! pyplot handler
266273 real (wp), dimension (:), intent (in ) :: x ! ! x values
267274 real (wp), dimension (:), intent (in ) :: y ! ! y values
@@ -270,7 +277,7 @@ subroutine add_3d_plot(me, x, y, z, label, linestyle, markersize, linewidth)
270277 character (len=* ), intent (in ) :: linestyle ! ! style of the plot line
271278 integer , intent (in ), optional :: markersize ! ! size of the plot markers
272279 integer , intent (in ), optional :: linewidth ! ! width of the plot line
273-
280+
274281 character (len= :), allocatable :: xstr ! ! x values strinfied
275282 character (len= :), allocatable :: ystr ! ! y values strinfied
276283 character (len= :), allocatable :: zstr ! ! z values strinfied
@@ -311,15 +318,15 @@ subroutine add_3d_plot(me, x, y, z, label, linestyle, markersize, linewidth)
311318 else
312319 error stop ' Error in add_3d_plot: pyplot class not properly initialized.'
313320 end if
314-
321+
315322 end subroutine add_3d_plot
316323! *****************************************************************************************
317324
318325! *****************************************************************************************
319326! > author: Jacob Williams
320327!
321328! Add a bar plot.
322-
329+
323330 subroutine add_bar (me , left , height , label , width , bottom , color )
324331
325332 class(pyplot), intent (inout ) :: me ! ! pyplot handler
@@ -329,7 +336,7 @@ subroutine add_bar(me, left, height, label, width, bottom, color)
329336 real (wp), dimension (:), intent (in ), optional :: width ! ! width values
330337 real (wp), dimension (:), intent (in ), optional :: bottom ! ! bottom values
331338 character (len=* ), intent (in ), optional :: color ! ! plot color
332-
339+
333340 character (len= :), allocatable :: xstr ! ! x axis values stringified
334341 character (len= :), allocatable :: ystr ! ! y axis values stringified
335342 character (len= :), allocatable :: wstr ! ! width values stringified
@@ -382,7 +389,7 @@ end subroutine add_bar
382389! the optional argument is not present.
383390
384391 subroutine optional_int_to_string (int_value , string_value , default_value )
385-
392+
386393 integer , intent (in ), optional :: int_value ! ! integer value
387394 character (len=* ), intent (out ) :: string_value ! ! integer value stringified
388395 character (len=* ), intent (in ) :: default_value ! ! default integer value
@@ -423,11 +430,11 @@ end subroutine integer_to_string
423430! Real vector to string.
424431
425432 subroutine vec_to_string (v , str , use_numpy )
426-
433+
427434 real (wp), dimension (:), intent (in ) :: v ! ! real values
428435 character (len= :), allocatable , intent (out ) :: str ! ! real values stringified
429436 logical , intent (in ) :: use_numpy ! ! activate numpy python module usage
430-
437+
431438 integer :: i ! ! counter
432439 integer :: istat ! ! IO status
433440 character (len= max_real_len) :: tmp ! ! dummy string
@@ -457,49 +464,49 @@ end subroutine vec_to_string
457464! a temporary filename is used, and the file is deleted after it is used.
458465
459466 subroutine execute (me , pyfile )
460-
467+
461468 class(pyplot), intent (inout ) :: me ! ! pytplot handler
462469 character (len=* ), intent (in ), optional :: pyfile ! ! name of the python script to generate
463-
470+
464471 integer :: istat ! ! IO status
465472 integer :: iunit ! ! IO unit
466- character (len= :), allocatable :: file ! ! file name
473+ character (len= :), allocatable :: file ! ! file name
467474 logical :: scratch ! ! if a scratch file is to be used
468475
469476 if (allocated (me% str)) then
470-
477+
471478 scratch = (.not. present (pyfile))
472-
479+
473480 ! file name to use:
474481 if (scratch) then
475482 file = trim (tmp_file) ! use the default
476483 else
477484 file = trim (pyfile) ! use the user-specified name
478485 end if
479-
486+
480487 ! open the file:
481488 open (newunit= iunit, file= file, status= ' REPLACE' , iostat= istat)
482489 if (istat/= 0 ) error stop ' Error opening file.'
483-
490+
484491 ! write to the file:
485492 write (iunit, ' (A)' ) me% str
486493
487494 ! run the file using python:
488495 call execute_command_line(python_exe// ' ' // file)
489-
496+
490497 ! close the file:
491498 if (scratch) then
492499 close (iunit, status= ' DELETE' , iostat= istat)
493500 else
494501 close (iunit, iostat= istat)
495502 end if
496503 if (istat/= 0 ) error stop ' Error closing file.'
497-
504+
498505 ! cleanup:
499506 if (allocated (file)) deallocate (file)
500507
501508 end if
502-
509+
503510 end subroutine execute
504511! *****************************************************************************************
505512
@@ -509,7 +516,7 @@ end subroutine execute
509516! Save the figure.
510517
511518 subroutine savefig (me , figfile , pyfile )
512-
519+
513520 class(pyplot), intent (inout ) :: me ! ! pyplot handler
514521 character (len=* ), intent (in ) :: figfile ! ! file name for the figure
515522 character (len=* ), intent (in ), optional :: pyfile ! ! name of the Python script to generate
@@ -521,6 +528,10 @@ subroutine savefig(me, figfile, pyfile)
521528 call me% add_str(' ax.legend(loc="best")' )
522529 call me% add_str(' ' )
523530 end if
531+ if (me% axis_equal) then
532+ call me% add_str(' ax.axis("equal")' )
533+ call me% add_str(' ' )
534+ end if
524535 call me% add_str(' plt.savefig("' // trim (figfile)// ' ")' )
525536
526537 ! run it:
@@ -535,4 +546,4 @@ end subroutine savefig
535546
536547! *****************************************************************************************
537548 end module pyplot_module
538- ! *****************************************************************************************
549+ ! *****************************************************************************************
0 commit comments