From 4d81e819170b895f247d23730a2237964be0fcd7 Mon Sep 17 00:00:00 2001 From: radek_poleski Date: Fri, 29 Nov 2024 07:02:13 +0100 Subject: [PATCH 01/13] clarified note on derivatives and longer lines in md file --- documents/00_MMv3_changes.md | 52 ++++++++++++------------------------ 1 file changed, 17 insertions(+), 35 deletions(-) diff --git a/documents/00_MMv3_changes.md b/documents/00_MMv3_changes.md index 87d3b037..c109d4a8 100644 --- a/documents/00_MMv3_changes.md +++ b/documents/00_MMv3_changes.md @@ -1,19 +1,15 @@ # MulensModel V3 There were two major goals for MulensModel V3: -- Allow for N sources (However, xallarap can only be used with binary source -models) -- Allow the user direct access to derivatives relative to the point lens model -(in addition to derivatives relative to chi2) +- Allow for N sources (However, xallarap can only be used with binary source models) +- Allow the user a direct access to partial derivatives of the magnification relative to the point lens model parameters (in addition to chi2 derivatives) Implementing these changes involved some major updates to the internal architecture, but these should mostly be invisible to the user (although they add new functionality). -We have also cleaned up some problems/bugs/features that will impact the user -experience: -- Shifted the convention of `alpha` by 180 deg to make MM compatible with -convention of Skowron et al. 2011. +We have also cleaned up some problems/bugs/features that will impact the user experience: +- Shifted the convention of `alpha` by 180 deg to make MM compatible with convention of Skowron et al. 2011. - Removing `astropy` units from microlensing parameters. - Generally improving consistency in naming conventions. - Deprecated functions and properties removed. @@ -35,21 +31,16 @@ Use `fix_blend_flux` instead. ### Model Class -- ADDED `get_magnification_curve()` and `get_magnification_curves()` -(for multi-source models). -- `get_lc()`: updated documentation to reflect that this returns MAGNITUDES -(not magnifications) +- ADDED `get_magnification_curve()` and `get_magnification_curves()` (for multi-source models). +- `get_lc()`: updated documentation to reflect that this returns MAGNITUDES (not magnifications) - `get_magnification()`: - REMOVED keyword `flux_ratio_constraint` - - default value of `separate` changed to None (which defaults to `True` if -`source_flux_ratio` is provided and to `False` otherwise). + - default value of `separate` changed to None (which defaults to `True` if `source_flux_ratio` is provided and to `False` otherwise). - REMOVED deprecated functions and attributes: - `plot_magnification()`: REMOVED keyword `flux_ratio_constraint`. - - `plot_lc()`: REMOVED keywords `data_ref`, `flux_ratio_constraint`, -`fit_blending`, `f_source`, and `f_blend`. + - `plot_lc()`: REMOVED keywords `data_ref`, `flux_ratio_constraint`, `fit_blending`, `f_source`, and `f_blend`. - `plot_trajectory()`: REMOVED keyword `show_data`. - - `set_default_magnification_method()`. Use -`Model.default_magnification_method = XXX`, instead. + - `set_default_magnification_method()`. Use `Model.default_magnification_method = XXX`, instead. - `magnification()` replaced by `get_magnification()`. - `reset_plot_properties()` @@ -60,21 +51,14 @@ immediately converted into a `ModelParameters` object, so many of these changes could affect the user experience, even if they had not been interacting directly with the `ModelParameters` class. -- `Astropy` units REMOVED (i.e., now everything is a `float`) from properties: -`t_star`, `t_eff`, `t_E`, `alpha`, `ds_dt`, `dalpha_dt`, `t_star_1`, `t_star_2`, -`gamma_parallel`, `gamma_perp`, and `gamma`. Also REMOVED from function -`get_alpha()`. +- `Astropy` units REMOVED (i.e., now everything is a `float`) from properties: `t_star`, `t_eff`, `t_E`, `alpha`, `ds_dt`, `dalpha_dt`, `t_star_1`, `t_star_2`, `gamma_parallel`, `gamma_perp`, and `gamma`. Also REMOVED from function `get_alpha()`. - Property `pi_E` REMOVED. Properties `pi_E_E` and `pi_E_N` are still there. -- Properties that are not defined now raise `AttributeError` (previously `rho` -was returning None, and some other ones raised `KeyError`). -- Warnings for unexpected values of angles (e.g., 1000 deg) are not raised -anymore. +- Properties that are not defined now raise `AttributeError` (previously `rho` was returning None, and some other ones raised `KeyError`). +- Warnings for unexpected values of angles (e.g., 1000 deg) are not raised anymore. - Changes in default values for `t_0_par` and `t_0_kep`: - - If `t_0_par` is not defined, then it defaults to `t_0_kep`, `t_0`, `t_0_1` -in that order. - - If `t_0_kep` is not defined, then it defaults to `t_0_par`, `t_0`, `t_0_1` -in that order. + - If `t_0_par` is not defined, then it defaults to `t_0_kep`, `t_0`, `t_0_1` in that order. + - If `t_0_kep` is not defined, then it defaults to `t_0_par`, `t_0`, `t_0_1` in that order. Also, REMOVED `which_parameters()` from modelparameters.py because it not very useful and it was very complicated. @@ -99,8 +83,7 @@ instead of the `times` argument. - ADDED: - `get_d_A_d_rho()` - `magnification_curve` and `magnification_curves` -- DEPRECATED subclass `FSPL_Derivatives`. Most its methods are replaced by -`PointLens` class(es) +- DEPRECATED subclass `FSPL_Derivatives`. Most its methods are replaced by `PointLens` class(es) - DEPRECATED: - `get_d_A_d_u_for_PSPL_model()` @@ -118,8 +101,7 @@ could be accessed instead through `FitData.magnification_curve.XXX()`. The PointLens and BinaryLens classes were subdivided into separate classes for each magnification method. -- Function `get_pspl_magnification()` from `pointlens.py` was removed. Use -classes listed in next point instead. +- Function `get_pspl_magnification()` from `pointlens.py` was removed. Use classes listed in next point instead. - Point Lens classes ADDED: - `PointSourcePointLensMagnification` - `FiniteSourceUniformGould94Magnification` @@ -150,4 +132,4 @@ classes listed in next point instead. - ADDED `EllipUtils`. - `MagnificationCurve`: - ADDED methods `get_d_A_d_params()` and `get_d_A_d_rho()`. - - ADDED property `methods_indices`. \ No newline at end of file + - ADDED property `methods_indices`. From 107278cadc07fd4a59f10183f82e05667aa54943 Mon Sep 17 00:00:00 2001 From: radek_poleski Date: Fri, 29 Nov 2024 07:21:22 +0100 Subject: [PATCH 02/13] github workflow action v3 -> v4 --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0f832999..c7e34264 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -42,7 +42,7 @@ jobs: CIBW_BUILD: ${{ matrix.cibw_build }} CIBW_SKIP: ${{ matrix.cibw_skip }} - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: wheelhouse path: ./wheelhouse/*.whl @@ -67,7 +67,7 @@ jobs: - name: Build package run: python setup.py sdist - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: sdist path: ./dist/*.tar.gz From 4f3812a51d077a5c5b9682d7782d055dd28181bc Mon Sep 17 00:00:00 2001 From: Justyna Wojtczak Date: Mon, 2 Dec 2024 19:48:59 +0100 Subject: [PATCH 03/13] Update publish.yml Update the name to prevent conflicts. --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c7e34264..fdd90cf5 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -44,7 +44,7 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: wheelhouse + name: wheelhouse-${{ matrix.os }}-${{ matrix.cibw_archs }}-${{ matrix.cibw_build }} path: ./wheelhouse/*.whl build_source: From d4953d1d8f189b8177001ef0539f534e303b4ca7 Mon Sep 17 00:00:00 2001 From: radek_poleski Date: Mon, 2 Dec 2024 21:53:57 +0100 Subject: [PATCH 04/13] trying to solve issue with publish.yml workflow --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index fdd90cf5..b0e86d15 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -26,7 +26,7 @@ jobs: # Skips PyPy os: [ubuntu-latest, macos-latest] cibw_archs: [auto64, arm64] - cibw_build: [cp38-*, cp39-*, cp310-*, cp311-*] + cibw_build: [cp38, cp39, cp310, cp311] cibw_skip: [pp*] exclude: - os: ubuntu-latest From 31ad02b900c7a1474fa853f8f5e565f1a6edb3ef Mon Sep 17 00:00:00 2001 From: radek_poleski Date: Wed, 4 Dec 2024 05:39:25 +0100 Subject: [PATCH 05/13] updating workfloa based on https://github.com/pypa/cibuildwheel/blob/main/examples/github-deploy.yml and reverting recent commit --- .github/workflows/publish.yml | 37 ++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b0e86d15..33098549 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -26,7 +26,7 @@ jobs: # Skips PyPy os: [ubuntu-latest, macos-latest] cibw_archs: [auto64, arm64] - cibw_build: [cp38, cp39, cp310, cp311] + cibw_build: [cp38-*, cp39-*, cp310-*, cp311-*] cibw_skip: [pp*] exclude: - os: ubuntu-latest @@ -44,7 +44,7 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: wheelhouse-${{ matrix.os }}-${{ matrix.cibw_archs }}-${{ matrix.cibw_build }} + name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} path: ./wheelhouse/*.whl build_source: @@ -69,8 +69,8 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: sdist - path: ./dist/*.tar.gz + name: cibw-sdist + path: dist/*.tar.gz publish: name: Publish to PyPI @@ -81,17 +81,26 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Download sdist artifacts to dist/ - uses: actions/download-artifact@v4.1.7 - with: - name: sdist - path: dist/ - - - name: Download wheelhouse artifacts to dist/ - uses: actions/download-artifact@v4.1.7 + steps: + - name: Download sdist and wheelhouse artifacts to dist/ + uses: actions/download-artifact@v4 with: - name: wheelhouse - path: dist/ + # unpacks all CIBW artifacts into dist/ + pattern: cibw-* + path: dist + merge-multiple: true + +# - name: Download sdist artifacts to dist/ +# uses: actions/download-artifact@v4 +# with: +# name: sdist +# path: dist/ + +# - name: Download wheelhouse artifacts to dist/ +# uses: actions/download-artifact@v4 +# with: +# name: wheelhouse +# path: dist/ - name: Publish package to PyPI # All files in dist/ are published From b728d4314a2a13cf7edee8a506ac41254c40d5ec Mon Sep 17 00:00:00 2001 From: radek_poleski Date: Wed, 4 Dec 2024 05:42:49 +0100 Subject: [PATCH 06/13] bug in .github/workflows/publish.yml format --- .github/workflows/publish.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 33098549..37f36815 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -81,7 +81,6 @@ jobs: steps: - uses: actions/checkout@v4 - steps: - name: Download sdist and wheelhouse artifacts to dist/ uses: actions/download-artifact@v4 with: From 4b5c239e5596b295764a506ee857f1aa2c72667e Mon Sep 17 00:00:00 2001 From: radek_poleski Date: Sat, 7 Dec 2024 04:11:28 +0100 Subject: [PATCH 07/13] notes on future changes --- documents/MM_v3.md | 14 ++------------ examples/example_16/ob03235_2_full.yaml | 1 + 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/documents/MM_v3.md b/documents/MM_v3.md index 302cb952..e9b0d4f3 100644 --- a/documents/MM_v3.md +++ b/documents/MM_v3.md @@ -1,16 +1,12 @@ -# What we want to change when going from v2.X.Y to v3.0.0? +# What we want to change when going from v3.X.Y to v4.0.0? Once the changes are accepted to be made, **mark them in the code using warnings.warn("XXX", FutureWarning)** and note it here. Also release a version that differs from previous one only in these warnings - this will allow users to correct their codes. Also give **suggested changes in warnings**. ### Major changes: - * search for all "deprecated" are remove it - * rename Caustics -> CausticsBinary and CausticsWithShear -> CausticsBinaryWithShear (and files) so that they're consistent with CausticsPointWithShear - ??? ### Minor changes: - * Delete ModelParameters.pi\_E and leave pi\_E\_N and pi\_E\_E - it is not really used and just complicates the code inside * Remove ModelParameters.as\_dict() because it is the same as ModelParameters.parameters * `ModelParameters.is_static` -> `is_lens_static` * ephemerides\_file -> ephemeris\_file - maybe @@ -18,16 +14,10 @@ Once the changes are accepted to be made, **mark them in the code using warnings * test\_MulensData.py - in test\_copy() remove warnings.catch\_warnings() because you remove coords, ra, and dec from init ### Yet unsorted/undecided: - * shift alpha by 180 deg if large update is made to follow Skowron et al. (2011) convention * remove MulensData.bad - see https://github.com/rpoleski/MulensModel/issues/40 * `Model.set\_times()` - `n\_epochs` should be None as default, so that we can check if both dt and `n\_epochs` were set * Caustics.get\_caustics() should return np.arrays, not lists * check all NotImplementedError and maybe remove some functions/options - * somehow change which\_parameters() in modelparameters.py - maybe remove * new class for a collection of datasets to make looping over datasets easier; also there will be data\_ref defined - * the same order of arguments in plotting functions (if possible) - * ModelParameters - all parameters should be float, not astropy.Quantity objects * see (this comment by Jen)[https://github.com/rpoleski/MulensModel/pull/15#issuecomment-1080879537] on how magnification methods are named and called in different parts of the code - -### Version 4: - * Add an Observatory class. + * Add an Observatory class - for terresital parallax diff --git a/examples/example_16/ob03235_2_full.yaml b/examples/example_16/ob03235_2_full.yaml index 4fd95e88..b6471c06 100644 --- a/examples/example_16/ob03235_2_full.yaml +++ b/examples/example_16/ob03235_2_full.yaml @@ -120,6 +120,7 @@ plots: best model: # You can skip the line below - the light curve will be plotted on screen. file: ob03235_2_model.png + # In case you want an interactive plot made using plotly: interactive : ob03235_2_model.html time range: 2452820 2452855 magnitude range: 19.3 16.9 From 7554eab99458475a69205fbeb5f58b812b4b28c2 Mon Sep 17 00:00:00 2001 From: radek_poleski Date: Sat, 7 Dec 2024 04:11:56 +0100 Subject: [PATCH 08/13] MM_v3.md -> MM_v4.md --- documents/{MM_v3.md => MM_v4.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documents/{MM_v3.md => MM_v4.md} (100%) diff --git a/documents/MM_v3.md b/documents/MM_v4.md similarity index 100% rename from documents/MM_v3.md rename to documents/MM_v4.md From b6b5b977bd807c57a4c865a69b89a8bf306c18da Mon Sep 17 00:00:00 2001 From: mjmroz Date: Sun, 8 Dec 2024 08:12:11 +0100 Subject: [PATCH 09/13] bug fix --- examples/example_16/ulens_model_fit.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/example_16/ulens_model_fit.py b/examples/example_16/ulens_model_fit.py index 85af3521..1a01d9da 100644 --- a/examples/example_16/ulens_model_fit.py +++ b/examples/example_16/ulens_model_fit.py @@ -3976,6 +3976,7 @@ def _make_interactive_lc_traces(self, f_source_0, f_blend_0, sizes, colors, opac if dataset.ephemerides_file is None: lc = self._model.get_lc( times=times, source_flux=f_source_0, blend_flux=f_blend_0, gamma=gamma, bandpass=bandpass) + times = times - subtract traces_lc.append(self._make_interactive_scatter_lc( times, lc, name, showlegend, colors[1], sizes[1], dash)) break From 8a3a15b9b19b689e74af5969f0a3ad0920f9c4bf Mon Sep 17 00:00:00 2001 From: mjmroz Date: Sun, 8 Dec 2024 08:14:59 +0100 Subject: [PATCH 10/13] bug fix --- examples/example_16/ulens_model_fit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example_16/ulens_model_fit.py b/examples/example_16/ulens_model_fit.py index 1a01d9da..83aa3eab 100644 --- a/examples/example_16/ulens_model_fit.py +++ b/examples/example_16/ulens_model_fit.py @@ -3965,7 +3965,7 @@ def _make_interactive_lc_traces(self, f_source_0, f_blend_0, sizes, colors, opac """ traces_lc = [] subtract = mm.utils.PlotUtils.find_subtract(subtract_2450000, subtract_2460000) - times = np.linspace(t_start, t_stop, num=5000) - subtract + times = np.linspace(t_start, t_stop, num=5000) if isinstance(name, type(None)): showlegend = False From 5916d79d9dd890b1c9f0e6dfe09b128324d3c75e Mon Sep 17 00:00:00 2001 From: mjmroz Date: Mon, 9 Dec 2024 06:28:40 +0100 Subject: [PATCH 11/13] Added a second Y-axis and changed the legend position in the interactive plot --- examples/example_16/ulens_model_fit.py | 60 ++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/examples/example_16/ulens_model_fit.py b/examples/example_16/ulens_model_fit.py index 83aa3eab..259e188a 100644 --- a/examples/example_16/ulens_model_fit.py +++ b/examples/example_16/ulens_model_fit.py @@ -47,7 +47,7 @@ raise ImportError('\nYou have to install MulensModel first!\n') -__version__ = '0.41.0' +__version__ = '0.41.1' class UlensModelFit(object): @@ -879,10 +879,6 @@ def _check_plots_parameters_best_model_interactive(self): """ Check if there is no problem with interactive best plot """ - if "second Y scale" in self._plots['best model']: - msg = "Interactive plot will not have a second Y scale. This feature is not yet implemented." - raise NotImplementedError(msg) - def _check_plots_parameters_best_model_Y_scale(self): """ Check if parameters for second Y scale make sense. @@ -3885,6 +3881,9 @@ def _prepare_interactive_layout(self, scale, kwargs_all, ylim, ylim_residuals): **kwargs_model, **kwargs_interactive ) + if "second Y scale" in self._plots['best model']: + layout = self._add_second_Y_axis_to_interactive_layout(layout, ylim) + layout = go.Layout(layout) return layout, kwargs_model, kwargs_interactive, kwargs def _get_kwargs_for_plotly_plot(self, scale): @@ -3931,10 +3930,10 @@ def _make_interactive_layout(self, ylim, ylim_residuals, height_ratios, hspace, tickwidth=sizes[6], linewidth=sizes[6], linecolor=colors[0], tickfont=font_base) kwargs_y = {'mirror': 'all', **kwargs_} kwargs_x = {'range': [t_start, t_stop], **kwargs_} - layout = go.Layout( + layout = dict( autosize=True, width=width, height=height, showlegend=True, - legend=dict( - x=1.02, y=.98, bgcolor=paper_bgcolor, bordercolor=colors[2], borderwidth=sizes[6], font=font_legend), + legend=dict(x=0, y=-0.2, yanchor='top', bgcolor=paper_bgcolor, bordercolor=colors[2], + borderwidth=sizes[6], font=font_legend), paper_bgcolor=paper_bgcolor, plot_bgcolor=paper_bgcolor, font=font_base, yaxis=dict(title_text='Magnitude', domain=[hsplit+(hspace/2), 1], range=ylim, **kwargs_y), yaxis2=dict(title_text='Residuals', domain=[0, hsplit-(hspace/2)], anchor="x", range=ylim_residuals, @@ -3945,6 +3944,45 @@ def _make_interactive_layout(self, ylim, ylim_residuals, height_ratios, hspace, ) return layout + def _add_second_Y_axis_to_interactive_layout(self, layout, ylim): + """Modifiing plotly.graph_objects.Layout object by adding second Y axis + """ + layout['yaxis']['mirror'] = False + layout['yaxis3'] = layout['yaxis'].copy() + layout['yaxis3'].update(dict(overlaying="y", side="right", scaleanchor="y")) + layout['yaxis3'].update(self._get_interactive_second_Y_axis_settings_(ylim)) + return layout + + def _get_interactive_second_Y_axis_settings_(self, ylim): + """Creats dictionary with settings for the second Y axis for the interactive plot + """ + (magnifications, color, label, labels, ax2) = self._interactive_second_Y_axis_settings() + (A_range, ref_fluxes) = self._second_Y_axis_get_fluxes(ylim) + out1, out2 = False, False + if magnifications == "optimal": + (magnifications, labels, out1) = self._second_Y_axis_optimal( + ax2, *A_range) + self._second_Y_axis_minor_ticks(ax2, magnifications, ref_fluxes) + flux = ref_fluxes[0] * np.array(magnifications) + ref_fluxes[1] + out2 = self._second_Y_axis_warnings(flux, labels, magnifications, + *A_range) + if out1 or out2: + return {} + ticks = mm.Utils.get_mag_from_flux(flux) + return dict(title_text=label, linecolor=color, tickmode='array', tickvals=ticks, ticktext=labels) + + def _interactive_second_Y_axis_settings(self): + """ + Get settings for the interactive second Y axis + """ + settings = self._plots['best model']["second Y scale"] + magnifications = settings['magnifications'] + color = settings.get("color", "black") + label = settings.get("label", "Magnification") + labels = settings.get("labels") + ax2 = plt.gca().twinx() + return (magnifications, color, label, labels, ax2) + def _get_time_span_data(self): """ Returning time span of datasets @@ -4050,7 +4088,11 @@ def _add_interactive_data_traces(self, kwargs_interactive, phot_fmt='mag', data_ dataset_index, times, y_value, y_err, xaxis='x', yaxis='y', showlegend=True, show_errorbars=show_errorbars, show_bad=show_bad, **kwargs_interactive) traces_data.extend(trace_data) - + if "second Y scale" in self._plots['best model'] and dataset_index == 0: + trace_data = self._make_one_interactive_data_trace( + dataset_index, times, y_value, y_err, xaxis='x', yaxis='y3', showlegend=False, + show_errorbars=show_errorbars, show_bad=show_bad, **kwargs_interactive) + traces_data.extend(trace_data) for trace in traces_data: self._interactive_fig.add_trace(trace) From 4d4957819173bc4f43fbf8e633a24b39059ddacc Mon Sep 17 00:00:00 2001 From: mjmroz Date: Mon, 9 Dec 2024 07:23:24 +0100 Subject: [PATCH 12/13] small improvement --- examples/example_16/ulens_model_fit.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/example_16/ulens_model_fit.py b/examples/example_16/ulens_model_fit.py index 259e188a..2d710179 100644 --- a/examples/example_16/ulens_model_fit.py +++ b/examples/example_16/ulens_model_fit.py @@ -4089,9 +4089,11 @@ def _add_interactive_data_traces(self, kwargs_interactive, phot_fmt='mag', data_ show_errorbars=show_errorbars, show_bad=show_bad, **kwargs_interactive) traces_data.extend(trace_data) if "second Y scale" in self._plots['best model'] and dataset_index == 0: + kwargs_interactive_secY = kwargs_interactive.copy() + kwargs_interactive_secY['opacity'] = 0. trace_data = self._make_one_interactive_data_trace( dataset_index, times, y_value, y_err, xaxis='x', yaxis='y3', showlegend=False, - show_errorbars=show_errorbars, show_bad=show_bad, **kwargs_interactive) + show_errorbars=show_errorbars, show_bad=show_bad, **kwargs_interactive_secY) traces_data.extend(trace_data) for trace in traces_data: self._interactive_fig.add_trace(trace) @@ -4136,10 +4138,11 @@ def _make_interactive_good_data_trace( def _make_interactive_data_trace(self, x, y, y_err, dataset, opacity, sizes, xaxis, yaxis, showlegend, show_errorbars, color_override=None, error_visible=True): """Creates single plotly.graph_objects.Scatter object for good or bad data.""" + label = dataset.plot_properties['label'] color = color_override if color_override else dataset.plot_properties['color'] error_y = dict(type='data', array=y_err, visible=error_visible, thickness=sizes[2], width=sizes[3]) marker = dict(color=color, size=sizes[0], line=dict(color=color, width=1)) - return go.Scatter(x=x, y=y, opacity=opacity, name=dataset.plot_properties['label'], mode='markers', + return go.Scatter(x=x, y=y, opacity=opacity, name=label, legendgroup=label, mode='markers', showlegend=showlegend, error_y=error_y, marker=marker, xaxis=xaxis, yaxis=yaxis) def _make_interactive_bad_data_trace(self, dataset, times, y_value, y_err, opacity, sizes, From c7434ec9c0099ad3c160ec9c0d604a3ca576d491 Mon Sep 17 00:00:00 2001 From: mjmroz Date: Tue, 10 Dec 2024 05:36:29 +0100 Subject: [PATCH 13/13] marge functions, add minor ticks, dynamic resolution of interactive lc --- examples/example_16/ulens_model_fit.py | 97 ++++++++++++-------------- 1 file changed, 44 insertions(+), 53 deletions(-) diff --git a/examples/example_16/ulens_model_fit.py b/examples/example_16/ulens_model_fit.py index 2d710179..c0e4a848 100644 --- a/examples/example_16/ulens_model_fit.py +++ b/examples/example_16/ulens_model_fit.py @@ -47,7 +47,7 @@ raise ImportError('\nYou have to install MulensModel first!\n') -__version__ = '0.41.1' +__version__ = '0.42.0' class UlensModelFit(object): @@ -3691,21 +3691,16 @@ def _mark_second_Y_axis_in_best_plot(self): Mark the second (right-hand side) scale for Y axis in the best model plot """ - (magnifications, labels, ylim, ax2) = self._second_Y_axis_settings() - (A_range, ref_fluxes) = self._second_Y_axis_get_fluxes(ylim) - out1, out2 = False, False - if magnifications == "optimal": - (magnifications, labels, out1) = self._second_Y_axis_optimal( - ax2, *A_range) - self._second_Y_axis_minor_ticks(ax2, magnifications, ref_fluxes) - flux = ref_fluxes[0] * np.array(magnifications) + ref_fluxes[1] - out2 = self._second_Y_axis_warnings(flux, labels, magnifications, - *A_range) - if out1 or out2: + (warning1, warning2, label, ylim, color, ax2, labels, ticks, minor_ticks) = self._get_second_Y_axis_settings() + if warning1 or warning2: ax2.get_yaxis().set_visible(False) - return + return + if minor_ticks is not None: + ax2.set_yticks(minor_ticks, minor=True) + ax2.set_ylabel(label).set_color(color) + ax2.spines['right'].set_color(color) + ax2.tick_params(axis='y', direction="in", which="both", colors=color) - ticks = mm.Utils.get_mag_from_flux(flux) try: # matplotlib version 3.5 or later ax2.set_yticks(ticks=ticks, labels=labels) except Exception: # matplotlib version 3.4.X or smaller @@ -3714,23 +3709,36 @@ def _mark_second_Y_axis_in_best_plot(self): ax2.set_ylim(ylim[0], ylim[1]) + def _get_second_Y_axis_settings(self, ylim=False): + """Creats settings for the second Y axis for the best model plot + """ + if not ylim: + ylim = plt.ylim() + (magnifications, color, label, labels, ax2) = self._second_Y_axis_settings() + (A_range, ref_fluxes) = self._second_Y_axis_get_fluxes(ylim) + warning1, warning2 = False, False + minor_ticks = None + if magnifications == "optimal": + (magnifications, labels, warning1) = self._second_Y_axis_optimal( + ax2, *A_range) + minor_ticks = self._second_Y_axis_minor_ticks(ax2, magnifications, ref_fluxes) + flux = ref_fluxes[0] * np.array(magnifications) + ref_fluxes[1] + warning2 = self._second_Y_axis_warnings(flux, labels, magnifications, *A_range) + ticks = mm.Utils.get_mag_from_flux(flux) + + return (warning1, warning2, label, ylim, color, ax2, labels, ticks, minor_ticks) + def _second_Y_axis_settings(self): """ - Get and apply settings for the second Y axis + Get settings for the second Y axis """ settings = self._plots['best model']["second Y scale"] magnifications = settings['magnifications'] color = settings.get("color", "black") label = settings.get("label", "Magnification") labels = settings.get("labels") - ylim = plt.ylim() - ax2 = plt.gca().twinx() - ax2.set_ylabel(label).set_color(color) - ax2.spines['right'].set_color(color) - ax2.tick_params(axis='y', direction="in", which="both", colors=color) - - return (magnifications, labels, ylim, ax2) + return (magnifications, color, label, labels, ax2) def _second_Y_axis_get_fluxes(self, ylim): """ @@ -3779,10 +3787,9 @@ def _second_Y_axis_minor_ticks(self, ax2, A_values, ref_fluxes): ax2.minorticks_on() minor_ticks_A = np.array(ax2.yaxis.get_ticklocs(minor=True)) minor_ticks_A = minor_ticks_A[~np.isin(minor_ticks_A, A_values)] - minor_ticks_flux = ref_fluxes[0] * minor_ticks_A + ref_fluxes[1] minor_ticks_mag = mm.Utils.get_mag_from_flux(minor_ticks_flux) - ax2.set_yticks(minor_ticks_mag, minor=True) + return minor_ticks_mag def _second_Y_axis_warnings(self, flux, labels, A_values, A_min, A_max): """ @@ -3943,45 +3950,28 @@ def _make_interactive_layout(self, ylim, ylim_residuals, height_ratios, hspace, xaxis2=dict(title_text=xtitle, anchor="y2", mirror='all', scaleanchor='x', matches='x', **kwargs_x) ) return layout - + def _add_second_Y_axis_to_interactive_layout(self, layout, ylim): """Modifiing plotly.graph_objects.Layout object by adding second Y axis """ layout['yaxis']['mirror'] = False layout['yaxis3'] = layout['yaxis'].copy() layout['yaxis3'].update(dict(overlaying="y", side="right", scaleanchor="y")) - layout['yaxis3'].update(self._get_interactive_second_Y_axis_settings_(ylim)) + settings = self._get_interactive_second_Y_axis_settings(ylim) + layout['yaxis3'].update(settings) return layout - def _get_interactive_second_Y_axis_settings_(self, ylim): + def _get_interactive_second_Y_axis_settings(self, ylim): """Creats dictionary with settings for the second Y axis for the interactive plot """ - (magnifications, color, label, labels, ax2) = self._interactive_second_Y_axis_settings() - (A_range, ref_fluxes) = self._second_Y_axis_get_fluxes(ylim) - out1, out2 = False, False - if magnifications == "optimal": - (magnifications, labels, out1) = self._second_Y_axis_optimal( - ax2, *A_range) - self._second_Y_axis_minor_ticks(ax2, magnifications, ref_fluxes) - flux = ref_fluxes[0] * np.array(magnifications) + ref_fluxes[1] - out2 = self._second_Y_axis_warnings(flux, labels, magnifications, - *A_range) - if out1 or out2: + (warning1, warning2, label, ylim, color, ax2, labels, ticks, + minor_ticks) = self._get_second_Y_axis_settings(ylim) + if warning1 or warning2: return {} - ticks = mm.Utils.get_mag_from_flux(flux) - return dict(title_text=label, linecolor=color, tickmode='array', tickvals=ticks, ticktext=labels) - - def _interactive_second_Y_axis_settings(self): - """ - Get settings for the interactive second Y axis - """ - settings = self._plots['best model']["second Y scale"] - magnifications = settings['magnifications'] - color = settings.get("color", "black") - label = settings.get("label", "Magnification") - labels = settings.get("labels") - ax2 = plt.gca().twinx() - return (magnifications, color, label, labels, ax2) + if minor_ticks is not None: + minor_ticks = dict(ticks='inside', tickmode='array', tickvals=minor_ticks) + return dict(title_text=label, linecolor=color, tickcolor=color, tickmode='array', tickvals=ticks, + ticktext=labels, minor=minor_ticks) def _get_time_span_data(self): """ @@ -4003,7 +3993,8 @@ def _make_interactive_lc_traces(self, f_source_0, f_blend_0, sizes, colors, opac """ traces_lc = [] subtract = mm.utils.PlotUtils.find_subtract(subtract_2450000, subtract_2460000) - times = np.linspace(t_start, t_stop, num=5000) + time_grid = int(t_stop-t_start)*7 + times = np.linspace(t_start, t_stop, num=time_grid) if isinstance(name, type(None)): showlegend = False