fortran66のブログ

fortran について書きます。

【メモ帳】forpy で Fortran から matplotlib  

Fortran からの作図

forpy を使って、サンプルを元に matplotlib を呼び出します。キーワード変数などの使い方を学びます。
github.com

実行例

べき乗のグラフを片対数のグラフにプロットします。
f:id:fortran66:20180902020931p:plain

ifort -fpp matplot.f90 forpy_mod.obj c:\IntelPython3\Libs\python36.lib

参考ページ: matplotlib の引数

matplotlib.pyplot.grid — Matplotlib 2.2.3 documentation

プログラム

作図は、メインルーチンの最後に、block...end block 構造の中に閉じ込めることで、スッキリできます。

program matplot
    implicit none
    real, parameter :: pi = 4 * atan(1.0)
    real, allocatable :: x(:), y(:)
    integer :: i, n
    
    n = 20
    x = [( 0.1 * i, i = 1, n)]
    y = 10.0**x
    
    block 
        use forpy_mod
        integer :: ierr
        type(module_py) :: plt
        type(tuple) :: args, arg1, arg2    
        type(ndarray) :: x_nd, y_nd
        type(dict) :: kwargs
!forpy        
        ierr = forpy_initialize()
        if (ierr == NO_NUMPY_ERROR) stop 'numpy not found!'
        if (ierr /= 0) stop 'forpy initialization error!'
!matplotlib        
        ierr = import_py(plt, 'matplotlib.pyplot')
        if (exception_matches(ImportError)) stop 'matplotlib not found!'
!main         
        ierr = ndarray_create(x_nd, x)
        ierr = ndarray_create(y_nd, y)
!  y-axis Log        
        ierr = tuple_create(arg1, 1)
        ierr = arg1%setitem(0, "log")
        ierr = call_py_noret(plt, 'yscale', arg1)
        call arg1%destroy()
!  Title        
        ierr = tuple_create(arg1, 1)
        ierr = arg1%setitem(0, "Log plot")
        ierr = call_py_noret(plt, 'title', arg1)
!  Grid x & y-axes (dasehed line)         
        ierr = tuple_create(args, 3)
        ierr = args%setitem(0, .true.)
        ierr = args%setitem(1, "both")
        ierr = args%setitem(2, "both")
        ierr = dict_create(kwargs)
        ierr = kwargs%setitem("linestyle", 'dashed')
        ierr = call_py_noret(plt, 'grid', args, kwargs)
!  set x, y data        
        ierr = tuple_create(arg2, 2)
        ierr = arg2%setitem(0, x_nd)
        ierr = arg2%setitem(1, y_nd)
!  plot         
        ierr = call_py_noret(plt, 'plot', arg2)
        ierr = call_py_noret(plt, 'show')
!clean up        
        call x_nd%destroy()
        call y_nd%destroy()
        call arg1%destroy()
        call arg2%destroy()
        call args%destroy()
        call kwargs%destroy()
        call plt%destroy()
! forpy finalize       
        call forpy_finalize()
    end block
end program matplot

素のままでは、tuple や list や dict を用意するのがめんどくさいので、先日作ったような tuple, list 生成関数を用意して用いるのが好ましいかと思います。

それにつけても、ブラウザに作図する WebAgg サーバーが ctrl-C で中々終了しないのでイライラします。

蛇マジむかつく!

追記 destroy 処理問題を気にしない場合

実行結果

f:id:fortran66:20180902142102p:plain

プログラム

メインルーチン
    program matplot
    implicit none
    real, parameter :: pi = 4 * atan(1.0)
    real, allocatable :: x(:), y(:)
    integer :: i, n
    
    n = 20
    x = [( 0.1 * i, i = 1, n)]
    y = 10.0**x
    
    block 
        use forpy_mod
        use m_tuple 
        integer :: ierr
        type(module_py) :: plt
        type(ndarray)   :: x_nd, y_nd
!forpy        
        ierr = forpy_initialize()
        if (ierr == NO_NUMPY_ERROR) stop 'numpy not found!'
        if (ierr /= 0) stop 'forpy initialization error!'
!matplotlib        
        ierr = import_py(plt, 'matplotlib.pyplot')
        if (exception_matches(ImportError)) stop 'matplotlib not found!'
!main         
        ierr = ndarray_create(x_nd, x)
        ierr = ndarray_create(y_nd, y)
        ierr = call_py_noret(plt, 'yscale', t_tuple("log"))
        ierr = call_py_noret(plt, 'title' , t_tuple("Matplotlib called from Fortran"))
        ierr = call_py_noret(plt, 'grid'  , t_tuple(.true., 'both', 'both'), t_dict("linestyle", 'dashed'))
        ierr = call_py_noret(plt, 'plot'  , t_tuple(x_nd, y_nd))
        ierr = call_py_noret(plt, 'show')
!clean up        
        call x_nd%destroy()
        call y_nd%destroy()
        call plt %destroy()
! forpy finalize       
        call forpy_finalize()
    end block
end program matplot

tuple, list, dict 用ルーチン

    module m_tuple
        use, intrinsic :: iso_fortran_env
        use forpy_mod
        implicit none
        type :: t_c
            class(*), pointer :: p => null()
        end type t_c
        type :: t_d
            character(:), pointer :: t => null() 
            class(*)    , pointer :: p => null()
        end type t_d
    contains
        subroutine tup_assign(tup, i, c)
            type(tuple), intent(in out) :: tup
            integer , intent(in) :: i
            class(*), intent(in) :: c
            integer :: ierr
            select type (c)
            type is (integer(int32))
                ierr = tup%setitem(i, c)
            type is (integer(int64))
                ierr = tup%setitem(i, c)
            type is (real(real32))
                ierr = tup%setitem(i, c)
            type is (real(real64))
                ierr = tup%setitem(i, c)
            type is (logical)
                ierr = tup%setitem(i, c)
            type is (character(*))
                ierr = tup%setitem(i, c)
            type is (tuple)
                ierr = tup%setitem(i, c)
            type is (list)
                ierr = tup%setitem(i, c)
            type is (dict)
                ierr = tup%setitem(i, c)
            type is (ndarray)
                ierr = tup%setitem(i, c)
            type is (object)
                ierr = tup%setitem(i, c)
            class default
                stop 'error tup_assign'
            end select
        end subroutine tup_assign
        
        type(tuple) function t_tuple(c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15) result(tup)
            class(*), intent(in), optional, target :: c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15
            integer :: ierr, i, n
            type(t_c) :: c(0:15) 
            if (present(c0 )) c( 0)%p => c0
            if (present(c1 )) c( 1)%p => c1
            if (present(c2 )) c( 2)%p => c2
            if (present(c3 )) c( 3)%p => c3
            if (present(c4 )) c( 4)%p => c4
            if (present(c5 )) c( 5)%p => c5
            if (present(c6 )) c( 6)%p => c6
            if (present(c7 )) c( 7)%p => c7
            if (present(c8 )) c( 8)%p => c8
            if (present(c9 )) c( 9)%p => c9
            if (present(c10)) c(10)%p => c10
            if (present(c11)) c(11)%p => c11
            if (present(c12)) c(12)%p => c12
            if (present(c13)) c(13)%p => c13
            if (present(c14)) c(14)%p => c14
            if (present(c15)) c(15)%p => c15
            n = 0
            do i = 0, 15
                if (associated(c(i)%p)) n = n + 1            
            end do
            ierr = tuple_create(tup, n)
            do i = 0, 15
                if (associated(c(i)%p)) call tup_assign(tup, i, c(i)%p)
            end do
            forall (i = 0:15) c(i)%p => null()
        end function t_tuple
    
        subroutine lis_append(lst, c)
            type(list), intent(in out) :: lst
            class(*), intent(in) :: c
            integer :: ierr
            select type (c)
            type is (integer(int32))
                ierr = lst%append(c)
            type is (integer(int64))
                ierr = lst%append(c)
            type is (real(real32))
                ierr = lst%append(c)
            type is (real(real64))
                ierr = lst%append(c)
            type is (logical)
                ierr = lst%append(c)
            type is (character(*))
                ierr = lst%append(c)
            type is (tuple)
                ierr = lst%append(c)
            type is (list)
                ierr = lst%append(c)
            type is (dict)
                ierr = lst%append(c)
            type is (ndarray)
                ierr = lst%append(c)
            type is (object)
                ierr = lst%append(c)
            class default
                stop 'error lis_append'
            end select
        end subroutine lis_append
        
        type(list) function t_list(c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15) result(lst)
            class(*), intent(in), optional, target :: c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15
            integer :: ierr, i
            type(t_c) :: c(0:15) 
            if (present(c0 )) c( 0)%p => c0
            if (present(c1 )) c( 1)%p => c1
            if (present(c2 )) c( 2)%p => c2
            if (present(c3 )) c( 3)%p => c3
            if (present(c4 )) c( 4)%p => c4
            if (present(c5 )) c( 5)%p => c5
            if (present(c6 )) c( 6)%p => c6
            if (present(c7 )) c( 7)%p => c7
            if (present(c8 )) c( 8)%p => c8
            if (present(c9 )) c( 9)%p => c9
            if (present(c10)) c(10)%p => c10
            if (present(c11)) c(11)%p => c11
            if (present(c12)) c(12)%p => c12
            if (present(c13)) c(13)%p => c13
            if (present(c14)) c(14)%p => c14
            if (present(c15)) c(15)%p => c15
            ierr = list_create(lst)
            do i = 0, 15
               if (associated(c(i)%p)) call lis_append(lst, c(i)%p)
            end do
            forall (i = 0:15) c(i)%p => null()
        end function t_list
    
        subroutine dic_assign(dic, t, d)
            type(dict), intent(in out) :: dic
            character(*), intent(in) :: t
            class(*)    , intent(in) :: d
            integer :: ierr
            select type (d)
            type is (integer(int32))
                ierr = dic%setitem(t, d)
            type is (integer(int64))
                ierr = dic%setitem(t, d)
            type is (real(real32))
                ierr = dic%setitem(t, d)
            type is (real(real64))
                ierr = dic%setitem(t, d)
            type is (logical)
                ierr = dic%setitem(t, d)
            type is (character(*))
                ierr = dic%setitem(t, d)
            type is (tuple)
                ierr = dic%setitem(t, d)
            type is (list)
                ierr = dic%setitem(t, d)
            type is (dict)
                ierr = dic%setitem(t, d)
            type is (ndarray)
                ierr = dic%setitem(t, d)
            type is (object)
                ierr = dic%setitem(t, d)
            class default
                stop 'error dic_assign'
            end select
        end subroutine dic_assign
    
        type(dict) function t_dict(t0, c0, t1, c1, t2, c2, t3, c3, t4, c4, t5, c5, t6, c6, t7, c7, t8, c8, t9, c9, & 
                                   t10, c10, t11, c11, t12, c12, t13, c13, t14, c14, t15, c15) result(dct)
            character(*), intent(in), optional, target :: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15
            class(*)    , intent(in), optional, target :: c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15
            integer :: ierr, i
            type(t_d) :: d(0:15) 
            if (present(t0 )) d( 0)%t => t0
            if (present(t1 )) d( 1)%t => t1
            if (present(t2 )) d( 2)%t => t2
            if (present(t3 )) d( 3)%t => t3
            if (present(t4 )) d( 4)%t => t4
            if (present(t5 )) d( 5)%t => t5
            if (present(t6 )) d( 6)%t => t6
            if (present(t7 )) d( 7)%t => t7
            if (present(t8 )) d( 8)%t => t8
            if (present(t9 )) d( 9)%t => t9
            if (present(t10)) d(10)%t => t10
            if (present(t11)) d(11)%t => t11
            if (present(t12)) d(12)%t => t12
            if (present(t13)) d(13)%t => t13
            if (present(t14)) d(14)%t => t14
            if (present(t15)) d(15)%t => t15
            if (present(c0 )) d( 0)%p => c0
            if (present(c1 )) d( 1)%p => c1
            if (present(c2 )) d( 2)%p => c2
            if (present(c3 )) d( 3)%p => c3
            if (present(c4 )) d( 4)%p => c4
            if (present(c5 )) d( 5)%p => c5
            if (present(c6 )) d( 6)%p => c6
            if (present(c7 )) d( 7)%p => c7
            if (present(c8 )) d( 8)%p => c8
            if (present(c9 )) d( 9)%p => c9
            if (present(c10)) d(10)%p => c10
            if (present(c11)) d(11)%p => c11
            if (present(c12)) d(12)%p => c12
            if (present(c13)) d(13)%p => c13
            if (present(c14)) d(14)%p => c14
            if (present(c15)) d(15)%p => c15
            ierr = dict_create(dct)
            do i = 0, 15
                if (associated(d(i)%p)) call dic_assign(dct, d(i)%t, d(i)%p)
            end do
            forall (i = 0:15) 
                d(i)%t => null()
                d(i)%p => null()
            end forall    
        end function t_dict
    end module m_tuple