diff --git a/scipost_django/graphs/forms.py b/scipost_django/graphs/forms.py index 8edd3cae909337a9adb2d5f4a4cd0d0706c9cda7..d5cd1e73b2f6eec50309aa33933772d8553aaa02 100644 --- a/scipost_django/graphs/forms.py +++ b/scipost_django/graphs/forms.py @@ -65,6 +65,23 @@ class GenericPlotOptionsForm(forms.Form): required=False, ) title = forms.CharField(label="Title", required=False) + fig_height = forms.FloatField( + label="Height", required=False, initial=4, min_value=1, max_value=30 + ) + fig_width = forms.FloatField( + label="Width", required=False, initial=6, min_value=1, max_value=30 + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.helper = FormHelper() + self.helper.layout = Layout( + Div(Field("theme"), css_class="col-12"), + Div(Field("title"), css_class="col-12"), + Div(Field("fig_height"), css_class="col-6"), + Div(Field("fig_width"), css_class="col-6"), + ) class PlotOptionsForm(forms.Form): @@ -135,24 +152,33 @@ class PlotOptionsForm(forms.Form): self.generic_plot_options_form: None, }.items(): + # If the form already has a layout, append it to the dynamic layout + if helper := getattr(form, "helper", None): + self.helper.layout.append(helper.layout) + continue + + # Otherwise, construct a layout from the form fields layout = Layout() if object_class not in (None, None.__class__): + + # Add the principal field to the layout + # This is usually the selector that will determine the other option fields principal_field_name = next(iter(form.fields.keys())) layout.append(Div(Field(principal_field_name), css_class="col-12")) - row_constructor = getattr( + get_row_field_layout = getattr( object_class, "get_plot_options_form_layout_row_content", None ) - if row_constructor: + if get_row_field_layout: try: object_class_prefix = object_class.Options.prefix or "" except AttributeError: object_class_prefix = "" - fields = row_constructor() + layout_fields = get_row_field_layout() # In-place prefixing of the layout-field names - prefix_layout_fields(object_class_prefix, fields) - layout.extend(fields) + prefix_layout_fields(object_class_prefix, layout_fields) + layout.extend(layout_fields) layout.extend( [ diff --git a/scipost_django/graphs/graphs/plotkind.py b/scipost_django/graphs/graphs/plotkind.py index 3646795aa821d51b06d460e12e399330cd46c315..cb4189c0b05ed9a98f392bde94db3a7f81284694 100644 --- a/scipost_django/graphs/graphs/plotkind.py +++ b/scipost_django/graphs/graphs/plotkind.py @@ -63,11 +63,11 @@ class PlotKind: x = list(range(len(y))) return x, y - def plot(self): + def plot(self, **kwargs): """ Plot the data on a the figure. """ - fig = self.get_figure() + fig = self.get_figure(**kwargs.get("fig_kwargs", {})) ax = fig.add_subplot(111) ax.set_title(f"{self.get_name()} plot of {self.plotter.model.__name__}") @@ -92,8 +92,8 @@ class PlotKind: class TimelinePlot(PlotKind): name = "timeline" - def plot(self): - fig = super().plot() + def plot(self, **kwargs): + fig = super().plot(**kwargs) ax = fig.get_axes()[0] ax.set_xlabel(self.plotter.date_key) @@ -191,11 +191,11 @@ class MapPlot(PlotKind): cax0.tick_params(axis="x", length=1.5, direction="out", which="minor") cax0.grid(False) - def plot(self): + def plot(self, **kwargs): from graphs.graphs import BASE_WORLD, OKLCH from matplotlib.colors import LinearSegmentedColormap, LogNorm - fig = self.get_figure() + fig = self.get_figure(**kwargs.get("fig_kwargs", {})) self.draw_colorbar(fig) ax, cax, _ = fig.get_axes() diff --git a/scipost_django/graphs/graphs/plotter.py b/scipost_django/graphs/graphs/plotter.py index 67b368a5d0f2fcfda7eb6c865c5e8e8c032de36c..509a7933006b1b12c674d1728e7f30fde2c470b7 100644 --- a/scipost_django/graphs/graphs/plotter.py +++ b/scipost_django/graphs/graphs/plotter.py @@ -80,8 +80,14 @@ class ModelFieldPlotter(ABC): ALL_MPL_THEMES.get(options.get("theme", None), "light"), ] ) - - fig = kind.plot() + fig = kind.plot( + fig_kwargs={ + "figsize": ( + options.get("fig_width", 6) or 6, + options.get("fig_height", 4) or 4, + ) + } + ) if title := options.get("title", None): fig.axes[0].set_title(title)