Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Major update of spectra, plotting, CL tools (#89)
Closes #84, closes #86, closes #87, closes #105 Summary of changes: - New command line tool ``euphonic-intensity-map`` for plotting weighted 2D Spectra e.g. Coherent neutron S(Q,w) - Existing command line tools ``euphonic-dispersion`` and ``euphonic-dos`` have been updated to also read force constants and Phonopy files. Arguments are also more consistent across tools so some may have changed, check the command line tool help for details. - New ``Spectrum1DCollection`` object for containing 1D spectra with a shared x-axis (e.g. phonon dispersion modes) - New ``plot_1d_to_axis`` and ``plot_2d_to_axis`` functions to allow plotting on specific axes - ``get_bin_centres`` and ``get_bin_edges`` utility functions on spectra - The ``ratio`` argument to ``plot_2d`` has been removed, it should no longer be required due to better management of relative axis sizes. - The ``btol`` argument to ``plot_1d`` has been removed, it is recommended to use ``Spectrum1D.split()`` or ``Spectrum1DCollection.split()`` instead. - The ``plot_dispersion`` function has been removed. It is now recommended to plot dispersion using ``plot_1d(QpointPhononModes.get_dispersion())``. See docs for details. Commits: * README Tweaks This is a somewhat superficial change to allow the creation of a feature branch PR for a more extensive set of work over multiple PRs * Spectrum2D: rework plot_2d to use NonUniformImage; new script Beginning work proposed in Issue #84 - Refactor plot_2d to use NonUniformImage. This cleans up a lot of the plotting logic, taking care of the irregular spacing for us. - Break actual axis plotting into separate function that can be re-used for custom/complex layouts, while plot_2d remains a "fire and forget" tool returning a Figure - Allow Normalize object to be passed, in preparation for implementation of multi-part plot with common colour scale - Dump script used for testing/prototyping into scripts directory; with a bit more work this should become a good tool for users. * Expand type-hinting of 2D spectrum plotting functions * Proof-of-concept: seekpath band structure returning multiple spectra Calling Seekpath is easy enough, but a bit of data manipulation is required to split the output into separate branches. Currently the spectrum for each segment is displayed separately. Having demonstrated that this works we can move to combining them in plot_2d. * Clean up neutron band structure script * plot_2d: accept a sequence of Spectrum2D as input Spectrum2D now uses subplots to present multiple spectra, as appropriate for Brillouin-zone band structure plots. The neutron band structure script has also had some minor upgrades. * Add broadening to neutron band structure script * neutron band structure script: fix y-units formatting * 2D plotting: further cleanup using nifty Euphonic and numpy features Some neat tricks were stolen from the 1D code * Neutron band structure script: Support more file formats * Neutron band structure: allow user to specify units * neutron_band_structure.py: report number of modes being calculated * 1D plot refactoring: separate phonons->Spectrum1D from plotting plot_dispersion is doing a useful job of generating Spectrum1D objects, but this is not accessible to the user. Split these functions. * Further 1D plot refactoring - Move main 1D plotting code into an internal "core" function - Type hinting - Lines option to neutron-band-structure; should be useful for testing work on band structure data - Some tweaking to avoid import loops * Spectrum classes: Spectrum1DCollection, Spectrum base class This setup for a spectrum base class is a bit of a hack: rename Spectrum1D to Spectrum, and inherit it to Spectrum1D. The purpose is to make sure that isinstance(spectrum, Spectrum1D) will FAIL if the spectrum is a Spectrum2D. Ideally we would have some shared code in a Spectrum ABC, and unique features in each subclass. But because there is a lot of "magic" around setting the properties of these classes with appropriate units, it is not so straightforward to establish abstract properties. * Expand tests of Spectrum1DCollection, fix issues as encountered * WIP: Spectrum1DCollection plotting * Spectrum as abstract base: separate Spectrum1D, Spectrum2D features This makes it far clearer which spectrum features are specifically implemented for Spectrum1D and Spectrum2D, without adding much redundancy. * 1D plot: typing/logic tweaks * Spectrum objects: implement split() method, test in Spectrum1D Initially considered an axis='x' option to support splitting in other directions. But as we're not implementing that now, there's no need to include the optional argument yet. * Spectrum1D split(): Expand test coverage This now gives full coverage for the base Spectrum class and Spectrum1D class. The new tests are a bit verbose compared to the existing setup, because the sample data is generated on the fly rather than read from JSON. At this point while features and tests are being developed this is a better workflow; it can be tidied up into JSON regression tests once we are satisfied with the functionality. * Basic tests: Spectrum1DCollection.split(), Spectrum2D.split() * Refactor 1D plots: use _plot_1d_core, handle breakpoints there - _split_line_idx are still being passed around, but the information is no longer used; instead, line breaks are inferred (just before plotting) by checking for identical neighbouring x-values * get_dispersion to method, & further simplification of plot_1d - The euphonic.util.get_dispersion() function is now a method on QpointPhononModes, returning a Spectrum1DCollection. - plot_dispersion() is now almost empty; it passes btol to split() and calls plot_1d. - btol option to plot_1d is removed; splitting should be performed before plotting - _get_gridspec_kw no longer deals with breakpoints * Major cleanup of neutron-band-structure using split() feature * Spectrum1D: clean up split() tests using existing JSON framework This process caught a bug: splitting can lead to numpy int64 values in the x_tick_labels, which do not play well with JSON serialisation. * Spectrum2D: clean up split() test using existing JSON framework * JSON Test data for spectrum.split() tests * Rework Spectrum1DCollection tests to use JSON references In the process, a couple of useful errors/sanity-checks were identified and included in Spectrum1DCollection * pint import tweak for oldlibs * neutron-band-structure review tweaks: emin/max, use to_spglib_cell() - Provide user arguments to set energy range - Default max to 5% above data - Default min to zero if data does not go below zero - Remove redundant implementation of to_spglib_cell() * Whitespace cleanup * Spectrum1DCollection test cleanup * QpointPhononModes: re-order methods to match docs * Refactor CLI tools so euphonic-dispersion can read FC - Move most of the file-reading and band structure construction logic to euphonic.cli.utils - Strip back neutron-band-structure to only produce spectrum plots * Tweak breakpoint positions for band structure plots * Fix some mistakes while plotting band structure from JSON * Fix dispersion splitting, regions; allow user to set energy-range - If we use the insert_gamma option to calculate_qpoint_phonon_modes, the split points from the input bandpath become incorrect. In order to guarantee the labels/split-points from seekpath, we inject the duplicate Gamma-points into band path data. - Add --e-min, --e-max options * euphonic-dispersion: update tests to reflect CLI argument changes * rename neutron_band_structure -> intensity_map This reflects a slightly broader scope, reading phonon mode data and plotting heatmaps. * import hackery to deal with old Pint versions * Add DOS mode to euphonic-intensity-map, make this the default * Test intensity-map; link broadening units to input arguments The output image maps would add quite a few MB of data to the repository, and we are looking to overhaul this with a proper image comparison process at a later stage. For now, just take a few slices. * Enable intensity-map to load q-point phonon mode data A bit more refactoring and code-sharing between euphonic-dispersion and euphonic-intensity-map means these now have essentially the same front-end and can load the same input files. * Add --v-min, --v-max arguments to intensity-map * Add .hdf5, .yaml band data support to dispersion, intensity-map - There is quite a bit of dispatching logic here that could use some proper testing. - The logic may need refactoring when we support another format that uses .yaml or .hdf5. * Argparse help updates: intensity-map, dispersion CLI * Add --asr option to dispersion, intensity-map CLI; with tests. Defaulting to no ASR correction because - changes to data should be explicit - and it's much easier to implement this way * Increase tol on extent for intensity map tests * Remove unused hashlib import * Set energy units after modes have been created * Move common args to cli utils * Update euphonic-dos to read force constants Also update it to be more consistent with dispersion and intensity-map * Update script test data * Allow reading of a wider variety of phonopy files Allow reading of renamed mesh/qpoints/bands.yaml/hdf5 and force_constants.hdf5 * Refactor script tests - Put script arguments and output files in test file rather than utils - Enable regeneration of test data files via Pytest (as a test with skip turned on by default) * Update script tests - Test all arguments and their short versions - Test most common combinations of arguments - Test all types of file reads (.castep_bin, .phonon, .yaml, .hdf5...) - Test save plot to file * Add function to get key for script test outputs Now that the input file is included in dos_args, dispersion_args etc., it cannot be used naively to produce a key with str.join, as this includes the absolute path, which will be different on different systems. Instead extract the directory name and filename and use those in the key. * Increase test tolerance if ASR present Otherwise fails on CI machines * Add CLI error tests - Remove code paths that can't be reached - Test appropriate errors are raised on incorrect inputs * Make small changes from review comments - Set atol for test_dispersion in if/else - Catch runtime warning in calculate_dos and add test * Update script data for new broadening * Add tests for figure labels/title to script tests * Make setting of 1D ax labels consitent with 2D * Test dispersion data as a series of 2D arrays Numpy can't automatically convert '3D' nested lists * Explicitly use empty strings for plot labels If left as None, older versions of Matplotlib set literal 'None' rather that having an empty label * Test plotting module Begin unit tests for _plot_1d_core * Plotting module tests: _plot_1d_core from Spectrum1DCollection * Plot tests: try old-fashioned add_subplot syntax Seem to be having problems with tests on minimum requirements * Plot tests: 1D tick labels * Plot tests: simple plot_1d * Plotting tests: test plot_dispersion; syntax tweak We shouldn't offer to forward *args to plot_1d because a) plot_1d doesn't take any extra positional args b) this follows a named arg, which isn't allowed * Plotting tests: matplotlib import error - Instead of raising a warning and error simultaneously, customise the error message - Be more specific: only ModuleNotFoundError should give message about installing matplotlib; other ImportError implies a different problem - Test this using the same trick as missing phonopy test; mock the import builtin to fail on Matplotlib. * Plotting: More 1D tests, a bit of cleanup - Tweak the logic for subplots; instead of checking whether the plots were squeezed to a single axes, set squeeze=False to guarantee 2D array, then flatten() to guarantee 1D series. - Context manager is unnecessary for patching with pytest-mock - Add tests for plot_1d with multiple subplots * Test euphonic.plot._plot_2d_core - This has a lot in common with the corresponding script test, so some infrastructure is factored out and shared. - Why test a private function? Well... - it makes it a lot easier to get complete coverage of plot_2d as we can now mock this function and just check it is called correctly - it probably won't be private forever, it's too useful * Test main euphonic.plot.plot_2d function * Plotting tests: axis tick labels utility function * Plot tests: tweak to Normalize setting for robustnes with old mpl * Test euphonic.plot.plot_2d with multiple segments * Tweak xticklabel test for matplotlib version compatibility * Just PEP8 things * Remove plot_dispersion, update docs to teach .get_dispersion() * Update plot_1d docs page * plotting docs - small fixes From @rebeccafair review comments * Fix test for matplotlib import error The imports were cleaned up, leading to import of 'matplotlib.pyplot' but not 'matplotlib'. The new import mocker should be more robust, working for 'matplotlib' or any 'matplotlib.*' * Fix code block formatting in docs * Make get_bin_centres/edges public and fix bugs - Spectrum1DCollection was returning incorrect centres/edges because the y_data in this case is 2D, so the wrong axis size was being checked. Have fixed this with a refactor and added a RuntimeError for unexpected axis sizes to avoid this in the future - get_bin_centres/edges for 1D now has no arguments, as this only makes sense for the x_axis. 2D still has bin_ax='x/y' - Added docstrings describing methods and caveats * Add tests for bin edges/centres RuntimeError * Add missing test data files * Remove unused Unit import from spectra.py * Update plot_1d/2d_core to plot_1d/2d_to_axis * Update docs - Update CL tool docs to mention force constants - Add docs for euphonic-intensity-map - Add sections on plot_1d/2d_to_axis - Add Spectrum1DCollection section - Add plotting dispersion link to QpointPhononModes - Remove outdated mention of refactor - Remove Jupyter notebook examples * Add changelog to docs * Update changelog * Remove mention of btol in plot_1d docstring * Fix changelog formatting * Fix doc typo * Small changes from PR review - Ensure old changelog entry for v0.2 -> v0.3 refactoring points to v0.3 documentation as the refactor.rst file has been deleted - Increase DOS grid size in doc euphonic-dos example - Change _is_bin_edge to raise ValueError instead of RuntimeError - Doc typo fixes Co-authored-by: Rebecca Fair <[email protected]>
- Loading branch information