|
12 | 12 | import cycler |
13 | 13 | import matplotlib.colors as mcolors |
14 | 14 | import matplotlib.cm as mcm |
| 15 | +from numbers import Number |
15 | 16 | from matplotlib import style, rcParams |
16 | 17 | try: |
17 | 18 | import IPython |
@@ -276,8 +277,7 @@ def _tabulate(rcdict): |
276 | 277 | """.strip()) |
277 | 278 |
|
278 | 279 | # "Global" settings and the lower-level settings they change |
279 | | -# NOTE: This whole section, declaring dictionaries and sets, takes 1ms |
280 | | -RC_CHILDREN = { |
| 280 | +_rc_children = { |
281 | 281 | 'cmap': ( |
282 | 282 | 'image.cmap', |
283 | 283 | ), |
@@ -729,6 +729,85 @@ def _update_from_file(file): |
729 | 729 | rcParams.update(rc) |
730 | 730 |
|
731 | 731 |
|
| 732 | +def _write_defaults(filename, comment=True, overwrite=False): |
| 733 | + """ |
| 734 | + Save a file to the specified path containing the default `rc` settings. |
| 735 | +
|
| 736 | + Parameters |
| 737 | + ---------- |
| 738 | + filename : str |
| 739 | + The path. |
| 740 | + comment : bool, optional |
| 741 | + Whether to "comment out" each setting. |
| 742 | + overwrite : bool, optional |
| 743 | + Whether to overwrite existing files. |
| 744 | + """ |
| 745 | + def _tabulate(rcdict): |
| 746 | + string = '' |
| 747 | + prefix = '# ' if comment else '' |
| 748 | + maxlen = max(map(len, rcdict)) |
| 749 | + NoneType = type(None) |
| 750 | + for key, value in rcdict.items(): |
| 751 | + if isinstance(value, cycler.Cycler): # special case! |
| 752 | + value = repr(value) |
| 753 | + elif isinstance(value, (str, Number, NoneType)): |
| 754 | + value = str(value) |
| 755 | + elif isinstance(value, (list, tuple)) and all( |
| 756 | + isinstance(val, (str, Number)) for val in value |
| 757 | + ): |
| 758 | + value = ', '.join(str(val) for val in value) |
| 759 | + else: |
| 760 | + raise ValueError( |
| 761 | + f'Failed to write rc setting {key} = {value!r}. ' |
| 762 | + 'Must be string, number, or list or tuple thereof, ' |
| 763 | + 'or None or a cycler.' |
| 764 | + ) |
| 765 | + space = ' ' * (maxlen - len(key) + 1) |
| 766 | + string += f'{prefix}{key}:{space}{value}\n' |
| 767 | + return string.strip() |
| 768 | + |
| 769 | + # Fill empty defaultParamsLong values with rcDefaultParamsShort |
| 770 | + # They are only allowed to be None in the *default dictionaries* because |
| 771 | + # they are immediately overwritten. However if users try to set them as |
| 772 | + # None in a .proplotrc file, may trigger error down the line. |
| 773 | + rc_parents = { |
| 774 | + child: parent |
| 775 | + for parent, children in _rc_children.items() |
| 776 | + for child in children |
| 777 | + } |
| 778 | + defaultParamsLong_filled = defaultParamsLong.copy() |
| 779 | + for key, value in defaultParamsLong.items(): |
| 780 | + if value is None: |
| 781 | + try: |
| 782 | + defaultParamsLong_filled[key] = rc_parents[key] |
| 783 | + except KeyError: |
| 784 | + raise RuntimeError( |
| 785 | + f'rcParamsLong param {key!r} has default value of None ' |
| 786 | + 'but has no rcParmsShort parent!' |
| 787 | + ) |
| 788 | + |
| 789 | + value = defaultParamsShort |
| 790 | + |
| 791 | + with open(filename, 'w') as f: |
| 792 | + f.write(f""" |
| 793 | +#--------------------------------------------------------------------- |
| 794 | +# Use this file to change the default proplot and matplotlib settings |
| 795 | +# The syntax is mostly the same as for matplotlibrc files |
| 796 | +# For descriptions of each setting see: |
| 797 | +# https://proplot.readthedocs.io/en/latest/rctools.html |
| 798 | +# https://matplotlib.org/3.1.1/tutorials/introductory/customizing.html |
| 799 | +#--------------------------------------------------------------------- |
| 800 | +# ProPlot short name settings |
| 801 | +{_tabulate(defaultParamsShort)} |
| 802 | +
|
| 803 | +# ProPlot long name settings |
| 804 | +{_tabulate(defaultParamsLong_filled)} |
| 805 | +
|
| 806 | +# Matplotlib settings |
| 807 | +{_tabulate(defaultParams)} |
| 808 | +""".strip()) |
| 809 | + |
| 810 | + |
732 | 811 | class rc_configurator(object): |
733 | 812 | """ |
734 | 813 | Magical abstract class for managing matplotlib |
@@ -1262,6 +1341,11 @@ def ipython_autosave(autosave=None): |
1262 | 1341 | pass |
1263 | 1342 |
|
1264 | 1343 |
|
| 1344 | +# Write defaults |
| 1345 | +_user_rc_file = os.path.join(os.path.expanduser('~'), '.proplotrc') |
| 1346 | +if not os.path.exists(_user_rc_file): |
| 1347 | + _write_defaults(_user_rc_file) |
| 1348 | + |
1265 | 1349 | #: Instance of `rc_configurator`. This is used to change global settings. |
1266 | 1350 | #: See :ref:`Configuring proplot` for details. |
1267 | 1351 | rc = rc_configurator() |
|
0 commit comments