#!/usr/bin/env python
"""
Generate the images and rst files for gallery of SfePy examples.
The following steps need to be made to regenerate the documentation with the
updated example files:
1. remove doc/examples/*::
$ rm -rf doc/examples/*
2. generate the files:
$ ./tools/gen_gallery.py
3. regenerate the documentation::
$ python setup.py htmldocs
"""
import sys
sys.path.append('.')
import os
import tempfile
import glob
import re
import shutil
import subprocess
from itertools import chain
from argparse import ArgumentParser, RawDescriptionHelpFormatter
import numpy as nm
import matplotlib.image as image
import sfepy
from sfepy.base.base import (get_default, ordered_iteritems,
import_file, output, Struct)
from sfepy.base.ioutils import (ensure_path, locate_files, remove_files,
edit_filename)
from sfepy.scripts.resview import pv_plot, get_camera_position
import pyvista as pv
omits = [
'__init__.py',
]
omit_images = [
'band_gaps_conf.py',
'dg_plot_1D.py',
'example_dg_common.py',
'homogenization_opt.py', # Is parameterized.
'linear_elasticity_opt.py', # Is parameterized.
'linear_homogenization_postproc.py',
'linear_homogenization_up.py', # Used in linear_elastic_mM.py.
'material_opt.py', # Very long calculation.
'nonlinear_homogenization.py',
'piezo_elasticity_micro.py', # Used in piezo_elasticity_macro.py.
'quantum_common.py',
]
omit_dirs = [
re.compile('.*output.*/').match,
]
custom = {
'acoustics/vibro_acoustic3d.py': {
'_Gamma0': {'view_2d': True, 'max_plots': 2},
'_Omega1': {'camera': [45, 55, 0.8]},
'_Omega2': {'camera': [45, 55, 0.8]},
},
'acoustics/acoustics3d.py': {
'_Omega_1': {
'camera': [75, 135, 1.4],
'grid_vector1': [1.2, 0, 0],
},
'_Omega_2': {
'camera': [75, 135, 1],
'grid_vector1': [1.2, 0, 0],
},
},
'acoustics/helmholtz_apartment.py': {
'': {
'fields': ['imag.E:wimag.E:f10%:p0', 'mat_id:p1'],
'force_view_3d': True,
'grid_vector1': [1.1, 0, 0],
'camera_position': [-9.22684,-8.37688,10.7623,
1.51653,0.122742,-0.646791,
0.472758,0.432784,0.767593],
'color_map': 'seismic',
},
},
'diffusion/cube.py': {
'': {'camera': [225, 55, 0.7]},
},
'diffusion/laplace_time_ebcs.py': {
'': {'camera': [225, 55, 0.7]},
},
'diffusion/laplace_fluid_2d.py': {
'': {'fields': ['phi:p0', 'phi:t50:p0']},
},
'diffusion/laplace_1d.py': {
'': {
'fields': ['t:wt:p0', 't:p0'],
'force_view_3d': True,
'camera_position': [0.243787,-1.51098,0.486608,
0.5,0,0,
0,0,1],
},
},
'dg/advection_1D.py': {
'': {
'fields': ['p_modal0:r:wp_modal0:p0', '1:vw:p0',
'p_modal1:r:wp_modal1:p1', '1:vw:p1',
'p_modal2:r:wp_modal2:p2', '1:vw:p2'],
'force_view_3d': True,
'camera_position': [0.300893,-2.41044,0.408743,
0.4,0,0.55728,
0,0,1],
'grid_vector2': [0, 0, 55],
'max_plots': 1,
'color_map': 'cool',
},
},
'diffusion/laplace_coupling_lcbcs.py': {
'': {
'fields': ['u1:wu1:p0', 'u1:vw:p0',
'u2:wu2:p1', 'u2:vw:p1'],
'force_view_3d': True,
},
},
'diffusion/laplace_iga_interactive.py': {
'command': 'python3 sfepy/examples/diffusion/laplace_iga_interactive.py -o output',
'result': 'output/concentric_circles.vtk',
'dim': 2,
'sfepy-view-options': {
'': {
},
},
},
'diffusion/laplace_refine_interactive.py': {
'command': 'python3 sfepy/examples/diffusion/laplace_refine_interactive.py output',
'result': 'output/hanging.vtk',
'sfepy-view-options': {
'': {
'fields': ['u:wu', '1:vw'],
'camera_position': [-1.27046,-1.02066,2.28476,
-0.0525852,0.116151,0.00474463,
0.169164,0.842974,0.510664],
},
},
},
'diffusion/laplace_shifted_periodic.py': {
'command': 'python3 sfepy/examples/diffusion/laplace_shifted_periodic.py',
'result': 'laplace_shifted_periodic.vtk',
'sfepy-view-options': {
'': {
'fields': ['u:wu:f0.5', '1:vw'],
'camera_position': [-1.42703,0.70237,1.33953,
-0.0817071,-0.0547046,0.0280939,
0.616241,-0.216582,0.757192],
},
},
},
'diffusion/poisson_iga.py': {
'': {
'fields': ['t:wt:p0', 't:vw:o0.4:p0'],
'force_view_3d': True,
'camera': [30, 60, 1.],
},
},
'diffusion/poisson_parallel_interactive.py': {
'command': 'python3 sfepy/examples/diffusion/poisson_parallel_interactive.py output-parallel -2 --shape=101,101',
'result': 'output-parallel/sol.h5',
'sfepy-view-options': {
'': {
'fields': ['u:wu', '1:vw'],
'camera_position': [-1.00607,-1.49437,0.843106,
0.0141441,-0.0501477,-0.0173962,
0.309532,0.315757,0.896932],
},
},
},
'diffusion/poisson_parametric_study.py': {
'command': 'sfepy-run sfepy/examples/diffusion/poisson_parametric_study.py',
'result': 'output/r_omega1/circles_in_square_0_1_2_3_4_5_6.vtk',
'dim': 2,
'sfepy-view-options': {
'': {
},
},
},
'diffusion/sinbc.py': {
'_t': {
'fields': ['t:wt:p0', '1:vw:p0'],
'force_view_3d': True,
'camera': [0, -45, 1.],
},
'_grad': {
'fields': ['grad:g:f0.01:p0', '1:vw:p0'],
'force_view_3d': True,
'camera': [0, -45, 1.5],
},
},
'diffusion/time_heat_equation_multi_material.py': {
'': {
'isosurfaces': 10,
'outline': True,
'camera': [-50, -230, 1],
},
},
'diffusion/time_poisson_interactive.py': {
'command': 'python3 sfepy/examples/diffusion/time_poisson_interactive.py -p',
'image': 'time_poisson_interactive_probe_04.png',
'result': 'domain.10.vtk',
'sfepy-view-options': {
'': {
},
},
},
'homogenization/linear_homogenization.py': {
'command': 'sfepy-run sfepy/examples/homogenization/linear_homogenization.py',
'result': 'output/corrs_le.vtk',
'sfepy-view-options': {
'': {
'max_plots': 3,
'camera_position': [-8.57147,2.10122,2.76537,
0.37,2.04405,2.14477,
0,0,1],
'show_labels': False,
'show_scalar_bars': False,
}
},
},
'homogenization/perfusion_micro.py': {
'command': 'sfepy-run sfepy/examples/homogenization/perfusion_micro.py',
'result': 'output/corrs_3d_2ch.vtk',
'sfepy-view-options': {
'_etaA_YM': {
'camera_position': [-1.69531,-0.966016,2.3648,
0.480252,0.486045,0.46669,
0.51024,0.292658,0.808707],
},
'_etaB_YM': {
'camera_position': [-1.69531,-0.966016,2.3648,
0.480252,0.486045,0.46669,
0.51024,0.292658,0.808707],
},
# '_gamma_A_1_YA': {
# 'camera_position': [-0.96887,-2.21765,1.25047,
# 1,0.4,0.5,
# 0.107002,0.198813,0.974179],
# 'grid_vector1': [1.2,0,0],
# },
# '_gamma_A_2_YA': {
# 'camera_position': [-0.96887,-2.21765,1.25047,
# 1,0.4,0.5,
# 0.107002,0.198813,0.974179],
# 'grid_vector1': [1.2,0,0],
# },
# '_gamma_A_3_YA': {
# 'camera_position': [-0.96887,-2.21765,1.25047,
# 1,0.4,0.5,
# 0.107002,0.198813,0.974179],
# 'grid_vector1': [1.2,0,0],
# },
# '_gamma_B_1_YB': {
# 'camera_position': [-0.96887,-2.21765,1.25047,
# 1,0.4,0.5,
# 0.107002,0.198813,0.974179],
# 'grid_vector1': [1.2,0,0],
# },
# '_gamma_B_2_YB': {
# 'camera_position': [-0.96887,-2.21765,1.25047,
# 1,0.4,0.5,
# 0.107002,0.198813,0.974179],
# 'grid_vector1': [1.2,0,0],
# },
# '_gamma_B_3_YB': {
# 'camera_position': [-0.96887,-2.21765,1.25047,
# 1,0.4,0.5,
# 0.107002,0.198813,0.974179],
# 'grid_vector1': [1.2,0,0],
# },
# '_gamma_m_YM': {
# 'camera_position': [-1.69531,-0.966016,2.3648,
# 0.480252,0.486045,0.46669,
# 0.51024,0.292658,0.808707],
# },
'_gamma_p_YM': {
'camera_position': [-1.69531,-0.966016,2.3648,
0.480252,0.486045,0.46669,
0.51024,0.292658,0.808707],
},
# '_oneA_YM': {
# 'camera_position': [-1.69531,-0.966016,2.3648,
# 0.480252,0.486045,0.46669,
# 0.51024,0.292658,0.808707],
# },
# '_oneB_YM': {
# 'camera_position': [-1.69531,-0.966016,2.3648,
# 0.480252,0.486045,0.46669,
# 0.51024,0.292658,0.808707],
# },
# '_piA_YA': {
# 'max_plots': 2,
# 'camera_position': [-2.02509,0.148141,3.9141,
# 0.913524,1.35355,0.462869,
# 0.714983,0.186315,0.673859],
# 'grid_vector1': [1.2,0,0],
# },
# '_piB_YB': {
# 'max_plots': 2,
# 'camera_position': [-2.02509,0.148141,3.9141,
# 0.913524,1.35355,0.462869,
# 0.714983,0.186315,0.673859],
# 'grid_vector1': [1.2,0,0],
# },
},
},
'homogenization/rs_correctors.py': {
'command': 'python3 sfepy/examples/homogenization/rs_correctors.py -n',
'result': 'corrs_elastic.vtk',
'sfepy-view-options': {
'': {
'max_plots': 2,
'camera_position': [1.16983,0.660181,7.63496,
1.16983,0.660181,
0,0,1,0],
},
},
},
'large_deformation/compare_elastic_materials.py': {
'command': 'python3 sfepy/examples/large_deformation/compare_elastic_materials.py -n',
'image': 'pressure_displacement.png',
'sfepy-view-options': {
},
},
'large_deformation/gen_yeoh_tl_up_interactive.py': {
'command': 'python3 sfepy/examples/large_deformation/gen_yeoh_tl_up_interactive.py -pn',
'image': 'gen_yeoh_tl_up_comparison.png',
'result': 'domain.10.vtk',
'sfepy-view-options': {
'': {
'fields': ['stress:wu:f1:p0', '1:vw:p0'],
'camera_position': [-1.89068,-2.47529,0.674151,
0.793688,0.209075,0.574171,
0,0,1],
}
},
},
'large_deformation/hyperelastic_tl_up_interactive.py': {
'command': 'python3 sfepy/examples/large_deformation/hyperelastic_tl_up_interactive.py -pn',
'image': 'hyperelastic_tl_up_comparison.png',
'result': 'domain.10.vtk',
'sfepy-view-options': {
'': {
'fields': ['stress:wu:f1:p0', '1:vw:p0'],
'camera_position': [-4.04955,-6.37091,3.78116,
2.06774,-0.866196,1.16309,
0.220544,0.208124,0.952914],
}
},
},
'linear_elasticity/dispersion_analysis.py': {
'command_0': 'python3 sfepy/examples/linear_elasticity/dispersion_analysis.py meshes/2d/special/circle_in_square.mesh --log-std-waves --eigs-only --no-show',
'command_1': 'python3 sfepy/scripts/plot_logs.py output/frequencies.txt -o output/frequencies.png -n',
'image': 'output/frequencies.png',
'sfepy-view-options': {
},
},
'linear_elasticity/elastic_contact_planes.py': {
'': {
'fields': ['u:wu:p0', '1:vw:p0'],
'camera': [225, 55, 0.7],
},
},
'linear_elasticity/elastic_contact_sphere.py': {
'': {
'fields': ['u:wu:p0', '1:vw:p0'],
'camera': [225, 55, 0.7],
},
},
'linear_elasticity/elastic_shifted_periodic.py': {
'': {'fields': ['von_mises_stress:r:wu:p0', '1:vw:p0']},
},
'linear_elasticity/elastodynamic.py': {
'': {
'fields': ['u:wu:f1e3:p0', '1:vw:p0',
'cauchy_strain:p1', 'cauchy_stress:p2'],
},
},
'linear_elasticity/elastodynamic_identification.py': {
'command_0': 'python3 sfepy/examples/linear_elasticity/elastodynamic_identification.py --output-dir=output/edi',
'image_0': 'output/edi/res00004.png',
'command_1': 'python3 sfepy/scripts/plot_logs.py output/edi/pars.txt -o output/edi/pars.png -n',
'image_1': 'output/edi/pars.png',
'sfepy-view-options': {
},
},
'linear_elasticity/its2D_4.py': {
'command_0': 'sfepy-run sfepy/examples/linear_elasticity/its2D_4.py',
'command_1': 'sfepy-probe sfepy/examples/linear_elasticity/its2D_4.py its2D.h5',
'image_0': 'its2D_0.png',
'image_1': 'its2D_1.png',
'result': 'its2D.h5',
'dim': 2,
'sfepy-view-options': {
'': {
},
},
},
'linear_elasticity/its2D_5.py': {
'command': 'sfepy-run sfepy/examples/linear_elasticity/its2D_5.py',
'image_0': 'its2D_probe_line0.png',
'image_1': 'its2D_probe_line1.png',
'result': 'its2D.vtk',
'dim': 2,
'sfepy-view-options': {
'': {
},
},
},
'linear_elasticity/its2D_interactive.py': {
'command': 'python3 sfepy/examples/linear_elasticity/its2D_interactive.py -p',
'image_0': 'its2D_interactive_probe_0.png',
'image_1': 'its2D_interactive_probe_1.png',
'result': 'its2D_interactive.vtk',
'dim': 2,
'sfepy-view-options': {
'': {
},
},
},
'linear_elasticity/linear_elastic_iga.py': {
'': {
'fields': ['u:wu:p0', '1:vw:p0'],
'camera': [-45, 55, 1],
},
},
'linear_elasticity/linear_elastic_interactive.py': {
'command': 'python3 sfepy/examples/linear_elasticity/linear_elastic_interactive.py',
'result': 'linear_elasticity.vtk',
'dim': 2,
'sfepy-view-options': {
'': {
'fields': ['u:wu:p0', '1:vw:p0'],
},
},
},
'linear_elasticity/linear_elastic_probes.py': {
'command': 'sfepy-run sfepy/examples/linear_elasticity/linear_elastic_probes.py',
'image_0': 'cylinder_probe_line.png',
'image_1': 'cylinder_probe_circle.png',
'image_2': 'cylinder_probe_ray.png',
'result': 'cylinder.vtk',
'sfepy-view-options': {
'': {
'fields': ['cauchy_stress:wu:p0', '1:vw:p0'],
'camera_position': [-0.0496419,-0.132205,0.0339214,
0.0495001,0.00309172,-0.00112878,
0.146854,0.145842,0.978348],
},
},
},
'linear_elasticity/linear_viscoelastic.py': {
'': {'camera': [225, 75, 0.88]}
},
'linear_elasticity/modal_analysis.py': {
'command': 'python3 sfepy/examples/linear_elasticity/modal_analysis.py -s 31,31 -n 3',
'result': 'eigenshapes.vtk',
'sfepy-view-options': {
'': {
'fields': ['strain000:wu000:f10%:p0', '1:vw:p0',
'strain001:wu001:f10%:p1', '1:vw:p1',
'strain002:wu002:f10%:p2', '1:vw:p2'],
'camera_position': [1.1,-0.1,5.41561,
1.1,-0.1,
0,0,1,0],
'grid_vector1': [1.2,0,0],
},
},
},
'linear_elasticity/modal_analysis_declarative.py': {
'': {
'fields': ['u003:wu003:f30%:p0', '1:vw:p0'],
'camera_position': [-2.30562,-2.2604,-0.325838,
-0.0714771,0.0374911,0.0287214,
-0.0245554,-0.129086,0.991329],
},
},
'linear_elasticity/multi_node_lcbcs.py': {
'': {
'fields': ['u:wu:e'],
'force_view_3d': True,
'camera_position': [0.175,0.125,0.735014,
0.175,0.125,0,
0,1,0],
},
},
'linear_elasticity/multi_point_constraints.py': {
'': {
'fields': ['u:wu:f1:p0', '1:vw:p0', 'u:gu:p0'],
'force_view_3d': True,
'camera_position': [0.0565,0.0434999,19.8951,
0.0565,0.0434999,0,
0,1,0],
},
},
'linear_elasticity/seismic_load.py': {
'': {
'fields': ['cauchy_stress:wu:f10:p0', '1:vw:p0'],
},
},
'linear_elasticity/shell10x_cantilever.py': {
'': {
'fields': ['u_disp:wu_disp:p0', '1:vw:p0',
'u_rot:p1', '1:vw:p1'],
'camera': [-45, 75, 1],
'grid_vector1': [1, 0, 0],
},
},
'linear_elasticity/shell10x_cantilever_interactive.py': {
'command': 'python3 sfepy/examples/linear_elasticity/shell10x_cantilever_interactive.py -t bend --plot --no-show output',
'image': 'output/shell10x_cantilever_convergence_bent.png',
'result': 'output/shell10x_cantilever.vtk',
'sfepy-view-options': {
'': {
'fields': ['u_disp:wu_disp:p0', '1:vw:p0',
'u_rot:p1', '1:vw:p1'],
'camera': [-45, 75, 1],
'grid_vector1': [1, 0, 0],
},
},
},
'linear_elasticity/truss_bridge.py': {
'': {
'view_2d': True,
'fields': ['u:wu:p0', '1:vw:p0', 'S:e:p1'],
'grid_vector1': [0, 2, 0],
},
},
'linear_elasticity/truss_bridge3d.py': {
'_Solid': {
'fields': ['u_solid:wu_solid:f1e3:p0'],
'camera_position': [-5.912, -6.64883, 1.80888,
5.05199, 2.28013, -1.49468,
0, 0, 1],
},
'_Struct': {
'fields': ['u_struct:wu_struct:f1e3:p0'],
'camera_position': [-5.912, -6.64883, 1.80888,
5.05199, 2.28013, -1.49468,
0, 0, 1],
},
},
'linear_elasticity/wedge_mesh.py': {
'command': 'sfepy-run sfepy/examples/linear_elasticity/wedge_mesh.py',
'result': 'beam_w14.vtk',
'sfepy-view-options': {
'': {
'fields': ['u:wu:e:o0.5'],
'camera_position': [0.927482,-0.574865,0.307926,
0.372897,0.120369,-0.0347131,
-0.326236,0.19556,0.924838],
}
},
},
'miscellaneous/live_plot.py': {
'command_0': 'python3 sfepy/examples/miscellaneous/live_plot.py -o output',
'command_1': 'python3 sfepy/scripts/plot_logs.py output/live_plot.txt -o output/live_plot.png -n',
'image_1': 'output/live_plot.png',
'command_2': 'python3 sfepy/scripts/plot_logs.py output/live_plot2.txt -o output/live_plot2.png -n',
'image_2': 'output/live_plot2.png',
'sfepy-view-options': {
},
},
'miscellaneous/refine_evp.py': {
'command': 'python3 sfepy/examples/miscellaneous/refine_evp.py --max-order=5 --max-refine=2 --fig-suffix=.png --no-show',
'image': 'output/h-refinement-0-laplace-lagrange-primme-none-a.png',
'sfepy-view-options': {
},
},
'multi_physics/biot_parallel_interactive.py': {
'command': 'python3 sfepy/examples/multi_physics/biot_parallel_interactive.py output-parallel',
'result': 'output-parallel/sol.h5',
'sfepy-view-options': {
'': {
'fields': ['u:t1000:p0', '1:vw:o0.1:p0', 'p:p1'],
'camera_position': [-0.740809,-2.67483,2.43604,
0.579298,-0.106475,0.0404841,
0.183213,0.618527,0.764106],
'grid_vector1': [1.2, 0, 0]
},
},
},
'multi_physics/piezo_elasticity.py': {
'': {'fields': ['u:g:p0', 'cauchy_strain:p1',
'elastic_stress:p2', 'piezo_stress:p3'],
'grid_vector1': [1.2, 0, 0],
'max_plots': 4},
},
'multi_physics/piezo_elastodynamic.py': {
'': {
'fields': ['p:wu:f2000:p0', '1:vw:wu:f2000:p0'],
'camera_position': [-0.0125588,-0.00559266,0.0117482,
0.00438669,0.00487109,0.00135715,
0.334487,0.333581,0.881387],
'color_map': 'inferno',
}
},
'multi_physics/thermal_electric.py': {
'command': 'python3 sfepy/examples/multi_physics/thermal_electric.py',
'result': 'sfepy/examples/multi_physics/output/circle_in_square.vtk',
'dim': 2,
'sfepy-view-options': {
'.el': {
},
'.10': {
},
},
},
'multi_physics/thermo_elasticity_ess.py': {
'': {
'fields': ['T:wu:f1e3:p0', '1:vw:p0'],
'camera': [-45, 75, 1],
},
},
'multi_physics/thermo_elasticity.py': {
'': {'camera': [225, 75, 0.9]}
},
'navier_stokes/stokes_slip_bc.py': {
'': {
'fields': ['u:g:f.25:p0', 'u:o.4:p0', 'p:p1'],
'camera': [-45, 55, 1],
'grid_vector1': [0, 1.2, 0]
},
},
'phononic/band_gaps.py': {
'command': 'sfepy-run sfepy/examples/phononic/band_gaps.py --phonon-band-gaps --phonon-plot -O plot_options={show=False,legend=True},fig_suffix=\'.png\'',
'image': 'sfepy/examples/phononic/output/band_gaps/band_gaps.png',
'result': 'sfepy/examples/phononic/output/band_gaps/evp.vtk',
'sfepy-view-options': {
'': {
'camera_position': [1.8,-1.2,7.28269,
1.8,-1.2,0,
0,1,0],
'grid_vector1': [1.2, 0, 0],
'grid_vector2': [0, -1.2, 0],
'max_plots': 4,
'show_labels': False,
'show_scalar_bars': False,
},
},
},
'phononic/band_gaps_rigid.py': {
'command': 'sfepy-run sfepy/examples/phononic/band_gaps_rigid.py --phonon-band-gaps --phonon-plot -O plot_options={show=False,legend=True},fig_suffix=\'_rigid.png\'',
'image': 'sfepy/examples/phononic/output/band_gaps_rigid/band_gaps_rigid.png',
'result': 'sfepy/examples/phononic/output/band_gaps_rigid/evp.vtk',
'sfepy-view-options': {
'': {
'fields': list(chain(
*[[f'u{ii:03d}:vs:o.4:p{ii}', f'u{ii:03d}:g:p{ii}']
for ii in range(12)]
)),
'camera_position': [1.8,-1.2,7.28269,
1.8,-1.2,0,
0,1,0],
'grid_vector1': [1.2, 0, 0],
'grid_vector2': [0, -1.2, 0],
'max_plots': 4,
'show_labels': False,
'show_scalar_bars': False,
},
},
},
'quantum/boron.py': {
'': {'fields': ['Psi000:p0', 'Psi001:p1', 'Psi002:p2', 'Psi003:p3'],
'grid_vector1': [1.2, 0, 0],
'max_plots': 4},
},
'quantum/hydrogen.py': {
'': {'fields': ['Psi000:p0', 'Psi001:p1', 'Psi002:p2', 'Psi003:p3'],
'grid_vector1': [1.2, 0, 0],
'max_plots': 4},
},
'quantum/oscillator.py': {
'': {'fields': ['Psi000:p0', 'Psi001:p1', 'Psi002:p2', 'Psi003:p3'],
'grid_vector1': [1.2, 0, 0],
'max_plots': 4},
},
'quantum/well.py': {
'': {'fields': ['Psi000:p0', 'Psi001:p1', 'Psi002:p2', 'Psi003:p3'],
'grid_vector1': [1.2, 0, 0],
'max_plots': 4},
},
}
[docs]
def resview_plot(filename, filename_out, options):
pv.set_plot_theme("document")
plotter = pv.Plotter(off_screen=True)
plotter = pv_plot([filename], options, plotter=plotter, use_cache=False)
if options.axes_visibility:
plotter.add_axes(**dict(options.axes_options))
if options.view_2d:
plotter.view_xy()
plotter.show(screenshot=filename_out, window_size=(800, 600))
else:
if options.camera_position is not None:
cpos = nm.array(options.camera_position)
cpos = cpos.reshape((3, 3))
elif options.camera:
zoom = options.camera[2] if len(options.camera) > 2 else 1.
cpos = get_camera_position(plotter.bounds,
options.camera[0], options.camera[1],
zoom=zoom)
else:
cpos = None
plotter.show(cpos=cpos, screenshot=filename_out, window_size=(800, 600))
[docs]
def run_resview_plot(*args):
"""
A fix for the problem that calling :func:`resview_plot()` directly often
terminates the program.
"""
from multiprocessing import Process
process = Process(target=resview_plot, args=args)
process.start()
process.join()
def _omit(filename, omits, omit_dirs):
omit = False
base = os.path.basename(filename)
if base in omits:
omit = True
for omit_dir in omit_dirs:
if omit_dir(filename) is not None:
omit = True
break
return omit
[docs]
def ebase2fbase(ebase):
return os.path.splitext(ebase)[0].replace(os.path.sep, '-')
def _make_fig_name(fig_base, fig_filename):
return fig_base + '-' + os.path.basename(fig_filename)
def _get_image_names(custom_options):
for key, val in custom_options.items():
if key.startswith('image'):
yield val
def _get_fig_filenames(ebase, images_dir):
fig_base = ebase2fbase(ebase)
if ebase in custom:
custom_options = custom.get(ebase)
if 'sfepy-view-options' in custom_options:
custom_view_options = custom_options['sfepy-view-options']
for fig_filename in _get_image_names(custom_options):
yield os.path.join(images_dir,
_make_fig_name(fig_base, fig_filename))
else:
custom_view_options = custom_options
if custom_view_options:
suffixes = sorted(custom_view_options.keys())
for suffix in suffixes:
yield os.path.join(images_dir, fig_base + suffix + '.png')
else:
yield os.path.join(images_dir, fig_base + '.png')
def _get_fig_filename(ebase, images_dir, suffix):
fig_base = ebase2fbase(ebase)
return os.path.join(images_dir, fig_base + suffix + '.png')
def _make_sphinx_path(path, relative=False):
if relative:
aux = path.replace(sfepy.data_dir, '')
prefix = ('..' + os.path.sep) * aux.count(os.path.sep)
sphinx_path = prefix[:-1] + aux
else:
sphinx_path = path.replace(sfepy.data_dir, '/..')
return sphinx_path
def _apply_commands(custom_options, ebase, images_dir):
for key, val in custom_options.items():
if key.startswith('command'):
cmd = custom_options[key]
subprocess.run(cmd.split()).check_returncode()
if key.startswith('image'):
shutil.copy(val,
os.path.join(images_dir,
_make_fig_name(ebase2fbase(ebase), val)))
[docs]
def apply_view_options(views, default):
out = {}
for kview, view in views.items():
ov = default.copy()
for k, v in view.items():
if k == 'fields':
fv = [k.split(':') for k in v]
fv = [(k[0], ':'.join(k[1:])) for k in fv]
setattr(ov, k, fv)
else:
setattr(ov, k, v)
out[kview] = ov
return out
[docs]
def generate_images(images_dir, examples_dir, pattern='*.py'):
"""
Generate images from results of running examples found in
`examples_dir` directory.
The generated images are stored to `images_dir`,
"""
from sfepy.applications import solve_pde
from sfepy.solvers.ts_solvers import StationarySolver
prefix = output.prefix
output_dir = tempfile.mkdtemp()
trunk = os.path.join(output_dir, 'result')
options = Struct(output_filename_trunk=trunk,
output_format='vtk',
save_ebc=False,
save_ebc_nodes=False,
save_regions=False,
save_regions_as_groups=False,
solve_not=False)
view_options = Struct(step=0,
fields=[], fields_map=[],
outline=False,
isosurfaces=0,
show_edges=False,
warp=None,
factor=1.,
opacity=1.,
color_map='viridis',
axes_options=[],
axes_visibility=False,
grid_vector1=None,
grid_vector2=None,
max_plots=3,
show_labels=False,
label_position=[-1, -1, 0, 0.2],
scalar_bar_size=[0.15, 0.06],
scalar_bar_position=[0.04, 0.92, 0, -1.5],
show_scalar_bars=True,
camera=[225, 75, 1],
camera_position=None,
view_2d=False,
force_view_3d=False,
show_step_time=False)
ensure_path(images_dir + os.path.sep)
for ex_filename in locate_files(pattern, examples_dir):
if _omit(ex_filename, omits + omit_images, omit_dirs):
continue
output.level = 0
output.prefix = prefix
ebase = ex_filename.replace(examples_dir, '')[1:]
output('trying "%s"...' % ebase)
_ebase = ebase.replace(os.path.sep, '/')
custom_options = custom.get(_ebase)
if custom_options and 'sfepy-view-options' in custom_options:
try:
_apply_commands(custom_options, ebase, images_dir)
filename = custom_options.get('result')
dim = custom_options.get('dim')
custom_view_options = custom_options['sfepy-view-options']
except subprocess.CalledProcessError:
filename = None
output('***** failed! *****')
else:
custom_view_options = custom_options
try:
problem, state = solve_pde(ex_filename, options=options)
try:
tsolver = problem.get_solver()
except ValueError:
suffix = None
else:
if isinstance(tsolver, StationarySolver):
suffix = None
else:
suffix = tsolver.ts.suffix % (tsolver.ts.n_step - 1)
filename = problem.get_output_name(suffix=suffix)
dim = problem.get_dim()
except KeyboardInterrupt:
raise
except:
filename = None
output('***** failed! *****')
if filename is not None:
if custom_view_options is not None:
views = apply_view_options(custom_view_options, view_options)
else:
views = {'': view_options.copy()}
for suffix, kwargs in views.items():
if dim in (1, 2) and not kwargs.force_view_3d:
kwargs.view_2d = True
kwargs.scalar_bar_position = [0.04, 0.92, 1.7, 0]
if kwargs.grid_vector1 is None:
kwargs.grid_vector1 = [1.2, 0, 0]
if kwargs.grid_vector2 is None:
kwargs.grid_vector2 = [0, -1.2, 0]
fig_filename = _get_fig_filename(ebase, images_dir, suffix)
fname = edit_filename(filename, suffix=suffix)
output('displaying results from "%s"' % fname)
disp_name = fig_filename.replace(sfepy.data_dir, '')
output('to "%s"...' % disp_name.lstrip(os.path.sep))
run_resview_plot(fname, fig_filename, kwargs)
output('...done')
remove_files(output_dir)
output('...done')
[docs]
def generate_thumbnails(thumbnails_dir, images_dir, scale=0.3):
"""
Generate thumbnails into `thumbnails_dir` corresponding to images in
`images_dir`.
"""
ensure_path(thumbnails_dir + os.path.sep)
output('generating thumbnails...')
filenames = glob.glob(os.path.join(images_dir, '*.png'))
for fig_filename in filenames:
ebase = fig_filename.replace(sfepy.data_dir, '').lstrip(os.path.sep)
output('"%s"' % ebase)
base = os.path.basename(fig_filename)
thumb_filename = os.path.join(thumbnails_dir, base)
image.thumbnail(fig_filename, thumb_filename, scale=scale)
output('...done')
_index = """\
.. _%s-index:
%s
%s
.. toctree::
:maxdepth: 2
"""
_image = '.. image:: %s'
_include = """\
.. _%s:
%s
%s
**Description**
%s
%s
:download:`source code <%s>`
.. literalinclude:: %s
"""
[docs]
def generate_rst_files(rst_dir, examples_dir, images_dir, pattern='*.py'):
"""
Generate Sphinx rst files for examples in `examples_dir` with images
in `images_dir` and put them into `rst_dir`.
Returns
-------
dir_map : dict
The directory mapping of examples and corresponding rst files.
"""
ensure_path(rst_dir + os.path.sep)
output('generating rst files...')
dir_map = {}
for ex_filename in locate_files(pattern, examples_dir):
if _omit(ex_filename, omits, omit_dirs):
continue
ebase = ex_filename.replace(examples_dir, '')[1:]
base_dir = os.path.dirname(ebase)
rst_filename = ebase2fbase(ebase) + '.rst'
dir_map.setdefault(base_dir, []).append((ex_filename, rst_filename))
for dirname, filenames in dir_map.items():
filenames = sorted(filenames, key=lambda a: a[1])
dir_map[dirname] = filenames
# Main index.
mfd = open(os.path.join(rst_dir, 'index.rst'), 'w')
mfd.write(_index % ('examples', 'Examples', '=' * 8))
for dirname, filenames in ordered_iteritems(dir_map):
# Subdirectory index.
ifd = open(os.path.join(rst_dir, '%s-index.rst' % dirname), 'w')
ifd.write(_index % (dirname + '-examples',
dirname, '=' * len(dirname)))
for ex_filename, rst_filename in filenames:
full_rst_filename = os.path.join(rst_dir, rst_filename)
output('"%s"' % rst_filename)
ebase = ex_filename.replace(examples_dir, '')[1:]
rst_base = os.path.splitext(rst_filename)[0]
rst_ex_filename = _make_sphinx_path(ex_filename)
try:
docstring = get_default(import_file(ex_filename).__doc__,
'missing description!')
except KeyboardInterrupt:
raise
except:
output('***** failed! *****')
docstring = 'example import failed!'
ifd.write(' %s <%s>\n' % (os.path.basename(ebase), rst_base))
fig_include = ''
for fig_filename in _get_fig_filenames(ebase, images_dir):
rst_fig_filename = _make_sphinx_path(fig_filename)
if os.path.exists(fig_filename):
fig_include += _image % rst_fig_filename + '\n'
else:
output(' warning: figure "%s" not found' % fig_filename)
# Example rst file.
fd = open(full_rst_filename, 'w', encoding='utf-8')
fd.write(_include % (rst_base, ebase, '=' * len(ebase),
docstring,
fig_include,
rst_ex_filename, rst_ex_filename))
fd.close()
ifd.close()
mfd.write(' %s-index\n' % dirname)
mfd.close()
output('...done')
return dir_map
_rst_empty_item = """\
- ..
"""
_rst_item = """\
%s - .. figure:: %s
:target: %s
:ref:`%s <%s>`
"""
_gallery_table = """\
.. list-table::
:align: center
:class: gallery
"""
_gallery_head = """\
.. only:: html
.. _gallery-index:
Gallery
=======
"""
[docs]
def generate_gallery(examples_dir, output_filename, doc_dir,
rst_dir, thumbnails_dir, dir_map, n_col=3):
"""
Generate the gallery rst file with thumbnail images and links to
examples.
Parameters
----------
output_filename : str
The output rst file name.
doc_dir : str
The top level directory of gallery files.
rst_dir : str
The full path to rst files of examples within `doc_dir`.
thumbnails_dir : str
The full path to thumbnail images within `doc_dir`.
dir_map : dict
The directory mapping returned by `generate_rst_files()`
n_col : int
The number of columns in the gallery table.
"""
output('generating %s...' % output_filename)
lines = [_gallery_head]
for dirname, filenames in ordered_iteritems(dir_map):
title = [' %s' % dirname.title().replace('_', ' '),
' ' + len(dirname) * '^' + '',
_gallery_table]
llines = []
icol = 0
for ex_filename, rst_filename in filenames:
ebase = ex_filename.replace(examples_dir, '')[1:]
link = os.path.splitext(rst_filename)[0]
try:
thumbnail_filename = next(_get_fig_filenames(ebase,
thumbnails_dir))
except StopIteration:
thumbnail_filename = ''
if not os.path.isfile(thumbnail_filename):
# Skip examples with no image (= failed examples).
output('warning: figure "%s" not found' % thumbnail_filename)
continue
thumbnail_name = thumbnail_filename.replace(doc_dir, '..')
path_to_file = os.path.join(examples_dir, ebase)
docstring = get_default(import_file(path_to_file).__doc__,
'missing description!')
docstring = docstring.replace('e.g.', 'eg:')
docstring = docstring.split('.')
label = docstring[0].strip()
label = label.replace('\n', ' ')
label = label.replace(' ', ' ')
llines.append(_rst_item % (' ' if icol else '*', thumbnail_name,
link + '.html', label, link))
icol = (icol + 1) % n_col
if icol > 0:
for j in range(icol, n_col):
llines.append(_rst_empty_item)
if len(llines) > 0:
lines += title + llines
else:
output('warning: no figures in "%s"' % dirname)
fd = open(output_filename, 'wt')
fd.write('\n'.join(lines))
fd.close()
output('...done')
helps = {
'doc_dir': 'top level directory of gallery files',
'pattern': 'example files search pattern [default: %(default)s]',
'no_images': 'do not (re)generate images',
'no_thumbnails': 'do not (re)generate thumbnails',
'output_filename': 'output file name [default: %(default)s]',
}
[docs]
def main():
parser = ArgumentParser(description=__doc__,
formatter_class=RawDescriptionHelpFormatter)
parser.add_argument('--version', action='version', version='%(prog)s')
parser.add_argument('-d', '--doc-dir', metavar='doc_dir',
action='store', dest='doc_dir',
default='doc', help=helps['doc_dir'])
parser.add_argument('-p', '--pattern', metavar='pattern',
action='store', dest='pattern',
default='*.py', help=helps['pattern'])
parser.add_argument('-n', '--no-images',
action='store_false', dest='images',
default=True, help=helps['no_images'])
parser.add_argument('--no-thumbnails',
action='store_false', dest='thumbnails',
default=True, help=helps['no_thumbnails'])
parser.add_argument('-o', '--output', metavar='output_filename',
action='store', dest='output_filename',
default='gallery.rst',
help=helps['output_filename'])
options = parser.parse_args()
rst_dir = 'examples'
doc_dir = os.path.realpath(options.doc_dir)
examples_dir = os.path.realpath('sfepy/examples')
full_rst_dir = os.path.join(doc_dir, rst_dir)
images_dir = os.path.join(doc_dir, 'images/gallery')
thumbnails_dir = os.path.join(images_dir, 'thumbnails')
output_filename = os.path.join(full_rst_dir, options.output_filename)
if options.images:
generate_images(images_dir, examples_dir, pattern=options.pattern)
if options.thumbnails:
generate_thumbnails(thumbnails_dir, images_dir)
dir_map = generate_rst_files(full_rst_dir, examples_dir, images_dir,
pattern=options.pattern)
generate_gallery(examples_dir, output_filename, doc_dir,
rst_dir, thumbnails_dir, dir_map)
if __name__ == '__main__':
main()