diff --git a/examples/plots-plotly/.gitignore b/examples/plots-plotly/.gitignore new file mode 100644 index 00000000..9cb46da1 --- /dev/null +++ b/examples/plots-plotly/.gitignore @@ -0,0 +1,3 @@ +signac.rc +signac_project_document.json +workspace/ diff --git a/examples/plots-plotly/README.md b/examples/plots-plotly/README.md new file mode 100644 index 00000000..2628537e --- /dev/null +++ b/examples/plots-plotly/README.md @@ -0,0 +1,3 @@ +# Plotly Plots Example + +To run this example, call `python init.py` and then `python dashboard.py run`. diff --git a/examples/plots-plotly/dashboard.py b/examples/plots-plotly/dashboard.py new file mode 100755 index 00000000..b06ed2c8 --- /dev/null +++ b/examples/plots-plotly/dashboard.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# Copyright (c) 2019 The Regents of the University of Michigan +# All rights reserved. +# This software is licensed under the BSD 3-Clause License. +from scipy.signal import coherence + +from signac_dashboard import Dashboard +from signac_dashboard.modules import PlotViewer, StatepointList, TextDisplay + + +class PlotDashboard(Dashboard): + def job_sorter(self, job): + return job.sp.get("coherence_time", -1) + + def job_title(self, job): + return f"Coherence time: {job.sp.coherence_time}" + + +def correlation_text(job): + return "Correlation coefficient: {:.5f}".format(job.doc["correlation"]) + + +def plotly_args(job): + # Visualization adapted from: + # https://matplotlib.org/gallery/lines_bars_and_markers/cohere.html + + # It's necessary to cast to list because the list elements of the job + # document are BufferedJSONAttrList, which is not serializable + signals_traces = [ + { + "x": list(job.doc["t"]), + "y": list(job.doc["s1"]), + "name": "s1", + }, + { + "x": list(job.doc["t"]), + "y": list(job.doc["s2"]), + "name": "s2", + }, + ] + signals_layout = { + "xaxis": { + "title": "time", + "range": [0, 2], + }, + "height": 200, + "margin": dict(t=30, b=40, l=40, r=0), + } + + dt = job.doc["t"][1] - job.doc["t"][0] + coherence_x, coherence_y = coherence( + job.doc["s1"], job.doc["s2"], nfft=256, fs=1.0 / dt + ) + coherence_traces = [ + { + "x": coherence_x.tolist(), + "y": coherence_y.tolist(), + } + ] + coherence_layout = { + "title": f"Coherence time = {job.sp.coherence_time}", + "xaxis": {"title": "frequency"}, + "yaxis": {"title": "coherence", "range": [0, 1]}, + "height": 200, + "margin": dict(t=30, b=40, l=40, r=0), + } + return [ + ("Signals", signals_traces, signals_layout), + ("Coherence", coherence_traces, coherence_layout), + ] + + +if __name__ == "__main__": + modules = [] + modules.append(StatepointList()) + modules.append(PlotViewer(plotly_args=plotly_args)) + modules.append(TextDisplay(name="Correlation", message=correlation_text)) + PlotDashboard(modules=modules).main() diff --git a/examples/plots-plotly/init.py b/examples/plots-plotly/init.py new file mode 100755 index 00000000..1d1495e5 --- /dev/null +++ b/examples/plots-plotly/init.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# Copyright (c) 2019 The Regents of the University of Michigan +# All rights reserved. +# This software is licensed under the BSD 3-Clause License. +import numpy as np +import signac + +project = signac.init_project("plots") + + +def plot_coherence(job): + # Data generation adapted from: + # https://matplotlib.org/gallery/lines_bars_and_markers/cohere.html + + print(f"Generating signals for coherence time {job.sp.coherence_time}, job {job}") + # Fixing random state for reproducibility + np.random.seed(job.sp.seed) + + dt = 0.01 + t = np.arange(0, 30, dt) + nse1 = np.random.randn(len(t)) # white noise 1 + nse2 = np.random.randn(len(t)) # white noise 2 + + # Two signals with a coherent part and a random part + s1 = np.sin(2 * np.pi * job.sp.coherence_time * t) + nse1 + s2 = np.sin(2 * np.pi * job.sp.coherence_time * t) + nse2 + + # Save the signal data + job.doc["t"] = t.tolist() + job.doc["s1"] = s1.tolist() + job.doc["s2"] = s2.tolist() + + # Save correlation coefficient + job.doc["correlation"] = np.corrcoef(s1, s2)[0, 1] + + +for i in range(30): + job = project.open_job({"coherence_time": i, "seed": 42}) + job.init() + plot_coherence(job)