Skip to content

Commit

Permalink
Merge pull request #646 from suzil/overlay-spectra-452
Browse files Browse the repository at this point in the history
Add support for overlaying spectra
  • Loading branch information
suzil authored Aug 28, 2022
2 parents a628f07 + eafc934 commit 3943b3c
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 128 deletions.
2 changes: 1 addition & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { PlotSpectrum } from "./components/PlotSpectrum";
import { palette } from "./constants";
import logo from "./radis.png";

const theme = createTheme({
export const theme = createTheme({
palette,
});

Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/DownloadButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ export const DownloadButton: React.FC<DownloadButtonProps> = ({
onClick,
}) => (
<Button
fullWidth
id="download-button"
disabled={disabled}
variant="contained"
color="primary"
variant="outlined"
onClick={onClick}
>
Download
Expand Down
78 changes: 53 additions & 25 deletions frontend/src/components/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import axios from "axios";
import { yupResolver } from "@hookform/resolvers/yup";
import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch";
import { PlotData, CalcSpectrumResponseData } from "../constants";
import { formSchema } from "../modules/formSchema";
import Button from "@mui/material/Button";
import { PlotSettings, Spectra } from "../constants";
import { formSchema } from "../modules/form-schema";
import { Database as DatabaseField } from "./fields/Database";
import { Mode } from "./fields/Mode";
import { TGas } from "./fields/TGas";
Expand All @@ -27,63 +28,66 @@ export interface Response<T> {
}

interface FormProps {
setPlotData: React.Dispatch<React.SetStateAction<PlotData | undefined>>;
setPlotSettings: React.Dispatch<
React.SetStateAction<PlotSettings | undefined>
>;
setError: React.Dispatch<React.SetStateAction<string | undefined>>;
setLoading: React.Dispatch<React.SetStateAction<boolean>>;
setProgress: React.Dispatch<React.SetStateAction<number>>;
setCalcSpectrumResponse: React.Dispatch<
React.SetStateAction<Response<CalcSpectrumResponseData> | undefined>
>;
spectrum: Spectra[];
setSpectrum: React.Dispatch<React.SetStateAction<Spectra[]>>;
}

export const Form: React.FunctionComponent<FormProps> = ({
setPlotData,
setPlotSettings,
setError,
setLoading,
setProgress,
setCalcSpectrumResponse,
spectrum,
setSpectrum,
}) => {
const [isNonEquilibrium, setIsNonEquilibrium] = useState(false);
const [showNonEquilibriumSwitch, setShowNonEquilibriumSwitch] =
useState(false);
const [useSlit, setUseSlit] = useState(false); // checking that user wants to apply the slit function or not in available modes
const [useSimulateSlitFunction, setUseSimulateSlitFunction] = useState(false); // checking the mode and enable or disable slit feature
const [disableDownloadButton, setDisableDownloadButton] = useState(true);
const [disableAddToPlotButton, setDisableAddToPlotButton] = useState(true);

const { control, handleSubmit, setValue, watch } = useForm<FormValues>({
defaultValues: { species: [{ molecule: "CO", mole_fraction: 0.1 }] },
resolver: yupResolver(formSchema),
});

const databaseWatch = watch("database");
const modeWatch = watch("mode");
React.useEffect(() => {
if (databaseWatch === Database.GEISA) {
setIsNonEquilibrium(false);
setShowNonEquilibriumSwitch(false);
} else {
setShowNonEquilibriumSwitch(true);
}
}, [databaseWatch]);

const modeWatch = watch("mode");
React.useEffect(() => {
if (modeWatch === "absorbance") {
setUseSimulateSlitFunction(false);
} else {
setUseSimulateSlitFunction(true);
}
if (modeWatch === "absorbance") {
setValue("simulate_slit", undefined);
} else {
setUseSimulateSlitFunction(true);
setValue("simulate_slit", 5);
}
}, [databaseWatch, modeWatch]);
setDisableAddToPlotButton(true);
}, [modeWatch]);

const handleBadResponse = (message: string) => {
setCalcSpectrumResponse(undefined);
setError(message);
};
const onSubmit = async (
data: FormValues,
endpoint: string
endpoint: string,
appendSpectra = false
): Promise<void> => {
if (useSlit == true) {
if (data.mode === "radiance_noslit") {
Expand All @@ -99,12 +103,6 @@ export const Form: React.FunctionComponent<FormProps> = ({
setDisableDownloadButton(true);
setLoading(true);
setError(undefined);
setPlotData({
max_wavenumber_range: data.max_wavenumber_range,
min_wavenumber_range: data.min_wavenumber_range,
mode: data.mode,
species: data.species,
});

import(/* webpackIgnore: true */ "./config.js").then(async (module) => {
if (endpoint === "calculate-spectrum") {
Expand All @@ -130,7 +128,25 @@ export const Form: React.FunctionComponent<FormProps> = ({
handleBadResponse(response.error);
setDisableDownloadButton(true);
} else {
setCalcSpectrumResponse(response);
setSpectrum([
...(appendSpectra ? spectrum : []),
{
species: data.species.map((s) => ({ ...s })),
database: data.database,
tgas: data.tgas,
trot: data.trot,
tvib: data.tvib,
pressure: data.pressure,
...response.data,
},
]);
setDisableAddToPlotButton(false);
setPlotSettings({
mode: data.mode,
units: data.mode.startsWith("absorbance")
? "-ln(I/I0)"
: response.data.units,
});
setDisableDownloadButton(false);
}
}
Expand Down Expand Up @@ -292,10 +308,22 @@ export const Form: React.FunctionComponent<FormProps> = ({
<UseNonEquilibriumCalculationsSwitch />
</Grid>
)}

<Grid item xs={12}>
<Grid item xs={6}>
<CalcSpectrumButton />
</Grid>
<Grid item xs={6}>
<Button
fullWidth
color="secondary"
variant="contained"
disabled={disableAddToPlotButton}
onClick={handleSubmit((data) =>
onSubmit(data, `calculate-spectrum`, true)
)}
>
Add to plot
</Button>
</Grid>
<Grid item xs={12}>
<DownloadButton
disabled={disableDownloadButton}
Expand Down
161 changes: 97 additions & 64 deletions frontend/src/components/Plot.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,47 @@
import React from "react";
import Plotly from "react-plotly.js";
import { LayoutAxis } from "plotly.js";
import { addSubscriptsToMolecule } from "../utils";
import { CalcSpectrumResponseData, palette } from "../constants";
import { PlotSettings, Spectra } from "../constants";
import { addSubscriptsToMolecule } from "../modules/molecule-subscripts";
import { Species } from "./types";

export interface PlotProps {
data: CalcSpectrumResponseData;
species: Species[];
min_wavenumber_range: number;
max_wavenumber_range: number;
mode: string;
spectrum: Spectra[];
plotSettings: PlotSettings;
}

const Plot_ = ({
data,
species,
min_wavenumber_range,
max_wavenumber_range,
const plotColors = [
"#f50057",
"#3f51b5",
"#00bcd4",
"#ffeb3b",
"#ff9800",
"#9c27b0",
"#2196f3",
"#009688",
"#ff5722",
"#795548",
"#607d8b",
"#e91e63",
"#673ab7",
];

mode,
}: PlotProps): JSX.Element => {
let modeLabel;
export const Plot_: React.FC<PlotProps> = ({
spectrum,
plotSettings: { mode, units },
}) => {
let modeLabel = "";
if (mode === "absorbance") {
modeLabel = "Absorbance";
data.units = "-ln(I/I0)";
} else if (mode.startsWith("transmittance")) {
modeLabel = "Transmittance";
} else if (mode.startsWith("radiance")) {
modeLabel = "Radiance";
} else {
throw new Error("Invalid mode");
}

const yaxis: Partial<LayoutAxis> = {
title: {
text: `${modeLabel}${data.units.length ? " (" + data.units + ")" : ""}`,
text: `${modeLabel}${units.length ? " (" + units + ")" : ""}`,
},
type: "linear",
autorange: true,
Expand All @@ -46,7 +53,7 @@ const Plot_ = ({
{
type: "buttons",
x: 0,
y: -0.3,
y: -0.37,
xanchor: "left",
yanchor: "top",
pad: { r: 10, t: 10 },
Expand Down Expand Up @@ -81,51 +88,77 @@ const Plot_ = ({
],
},
];

const formatSpectraName = ({
database,
tgas,
trot,
tvib,
pressure,
species,
}: {
database: string;
tgas: number;
trot?: number;
tvib?: number;
pressure: number;
species: Species[];
}) => {
const speciesFormatted = species
.map(
({ molecule, mole_fraction }) =>
`${addSubscriptsToMolecule(molecule)} (χ=${mole_fraction})`
)
.join(", ");
let formatted = `${speciesFormatted} ${database.toUpperCase()}, Pressure=${pressure} bar, Tgas=${tgas} K`;
if (trot) {
formatted += `, Trot=${trot} K, Tvib=${tvib} K`;
}
return formatted;
};

return (
<>
{
<Plotly
className="Plot"
data={[
{
x: data.x,
y: data.y,
type: "scatter",
marker: { color: palette.secondary.main },
},
]}
layout={{
width: 800,
height: 600,
title: `Spectrum for ${species
.map(({ molecule, mole_fraction }) => {
const moleculeWithSubscripts = addSubscriptsToMolecule(
molecule || ""
);
return `${moleculeWithSubscripts}${moleculeWithSubscripts.sub()} = ${
mole_fraction as number
})`;
})
.join(", ")}`,
font: { family: "Roboto", color: "#000" },
xaxis: {
range: [min_wavenumber_range, max_wavenumber_range],
title: { text: "Wavenumber (cm⁻¹)" },
rangeslider: {
// TODO: Update typing in DefinitelyTyped
// @ts-ignore
autorange: true,
// @ts-ignore
yaxis: { rangemode: "auto" },
},
type: "linear",
},
yaxis,
updatemenus,
}}
/>
}
</>
<Plotly
className="Plot"
data={spectrum.map(
({ x, y, species, database, tgas, trot, tvib, pressure }, index) => ({
x,
y,
type: "scatter",
marker: { color: plotColors[index % plotColors.length] },
name: formatSpectraName({
database,
species,
tgas,
trot,
tvib,
pressure,
}),
})
)}
layout={{
width: 800,
height: 600,
title: "Spectrum",
font: { family: "Roboto", color: "#000" },
xaxis: {
autorange: true,
title: { text: "Wavenumber (cm⁻¹)" },
rangeslider: {
// TODO: Update typing in DefinitelyTyped
// @ts-ignore
autorange: true,
// @ts-ignore
yaxis: { rangemode: "auto" },
},
type: "linear",
},
yaxis,
updatemenus,
showlegend: true,
legend: { orientation: "h", y: -0.6, x: 0 },
}}
/>
);
};

Expand Down
Loading

0 comments on commit 3943b3c

Please sign in to comment.