Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions datawrapper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@
ValueLabelMode,
ValueLabelPlacement,
)
from datawrapper.charts.mixins import (
CustomRangeMixin,
CustomTicksMixin,
GridDisplayMixin,
GridFormatMixin,
)
from datawrapper.exceptions import (
FailedRequestError,
InvalidRequestError,
Expand Down Expand Up @@ -123,6 +129,10 @@
"ValueLabelMode",
"ValueLabelPlacement",
"get_country_flag",
"CustomRangeMixin",
"CustomTicksMixin",
"GridFormatMixin",
"GridDisplayMixin",
"FailedRequestError",
"InvalidRequestError",
"RateLimitError",
Expand Down
12 changes: 12 additions & 0 deletions datawrapper/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,10 @@ def export_chart(
) -> Path | Image:
"""Exports a chart, table, or map.

.. deprecated::
Use the object-oriented chart classes instead (e.g., BarChart, LineChart).
This method will be removed in a future version.

Parameters
----------
chart_id : str
Expand Down Expand Up @@ -1210,6 +1214,14 @@ def export_chart(
Path | Image
The file path to the exported image or an Image object displaying the image.
"""
warnings.warn(
"export_chart() is deprecated and will be removed in a future version. "
"Use the object-oriented chart classes instead. "
"Example: chart = BarChart.get(chart_id='abc123'); png_data = chart.export_png(); Path('chart.png').write_bytes(png_data)",
Comment thread
palewire marked this conversation as resolved.
DeprecationWarning,
stacklevel=2,
)

_query = {
"unit": unit,
"mode": mode,
Expand Down
10 changes: 10 additions & 0 deletions datawrapper/charts/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
ValueLabelPlacement,
)
from .line import AreaFill, Line, LineChart, LineSymbol, LineValueLabel
from .mixins import (
CustomRangeMixin,
CustomTicksMixin,
GridDisplayMixin,
GridFormatMixin,
)
from .models import (
Annotate,
ColumnFormat,
Expand All @@ -56,6 +62,10 @@
"Annotate",
"ColumnFormat",
"ColumnFormatList",
"CustomRangeMixin",
"CustomTicksMixin",
"GridFormatMixin",
"GridDisplayMixin",
"ArrowHead",
"ConnectorLineType",
"DateFormat",
Expand Down
194 changes: 57 additions & 137 deletions datawrapper/charts/area.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,28 @@
from .base import BaseChart
from .enums import (
DateFormat,
GridDisplay,
GridLabelAlign,
GridLabelPosition,
LineInterpolation,
NumberFormat,
PlotHeightMode,
)
from .mixins import (
CustomRangeMixin,
CustomTicksMixin,
GridDisplayMixin,
GridFormatMixin,
)
from .serializers import (
ColorCategory,
CustomRange,
CustomTicks,
ModelListSerializer,
PlotHeight,
)


class AreaChart(BaseChart):
class AreaChart(
GridDisplayMixin, GridFormatMixin, CustomRangeMixin, CustomTicksMixin, BaseChart
):
"""A base class for the Datawrapper API's area chart."""

model_config = ConfigDict(
Expand Down Expand Up @@ -59,70 +64,6 @@ class AreaChart(BaseChart):
description="The type of datawrapper chart to create",
)

#
# Horizontal axis (X-axis)
#

#: The custom range for the x axis
custom_range_x: list[Any] | tuple[Any, Any] = Field(
default_factory=lambda: ["", ""],
alias="custom-range-x",
description="The custom range for the x axis",
)

#: The custom ticks for the x axis
custom_ticks_x: list[Any] = Field(
default_factory=list,
alias="custom-ticks-x",
description="The custom ticks for the x axis",
)

#: The formatting for the x grid labels (use DateFormat or NumberFormat enum or custom format strings)
x_grid_format: DateFormat | NumberFormat | str = Field(
default="auto",
alias="x-grid-format",
description="The formatting for the x grid labels. Use DateFormat for temporal data, NumberFormat for numeric data, or provide custom format strings.",
)

#: Whether to show the x grid
x_grid: GridDisplay | str = Field(
default="off",
alias="x-grid",
description="Whether to show the x grid. The 'on' setting shows lines.",
)

#
# Vertical axis (Y-axis)
#

#: The custom range for the y axis
custom_range_y: list[Any] | tuple[Any, Any] = Field(
default_factory=lambda: ["", ""],
alias="custom-range-y",
description="The custom range for the y axis",
)

#: The custom ticks for the y axis
custom_ticks_y: list[Any] = Field(
default_factory=list,
alias="custom-ticks-y",
description="The custom ticks for the y axis",
)

#: The formatting for the y grid labels (use DateFormat or NumberFormat enum or custom format strings)
y_grid_format: DateFormat | NumberFormat | str = Field(
default="",
alias="y-grid-format",
description="The formatting for the y grid labels. Use DateFormat for temporal data, NumberFormat for numeric data, or provide custom format strings.",
)

#: Whether to show the y grid
y_grid: GridDisplay | str = Field(
default="on",
alias="y-grid",
description="Whether to show the y grid. The 'on' setting shows lines.",
)

#: The labeling of the y grid labels
y_grid_labels: GridLabelPosition | str = Field(
default="auto",
Expand Down Expand Up @@ -313,52 +254,48 @@ def serialize_model(self) -> dict:
model = super().serialize_model()

# Add chart specific properties
model["metadata"]["visualize"].update(
{
# Horizontal axis
"custom-range-x": CustomRange.serialize(self.custom_range_x),
"custom-ticks-x": CustomTicks.serialize(self.custom_ticks_x),
"x-grid-format": self.x_grid_format,
"x-grid": self.x_grid,
# Vertical axis
"custom-range-y": CustomRange.serialize(self.custom_range_y),
"custom-ticks-y": CustomTicks.serialize(self.custom_ticks_y),
"y-grid-format": self.y_grid_format,
"y-grid": self.y_grid,
"y-grid-labels": self.y_grid_labels,
"y-grid-label-align": self.y_grid_label_align,
# Customize areas
"area-opacity": self.area_opacity,
"base-color": self.base_color,
"interpolation": self.interpolation,
"sort-areas": self.sort_areas,
"stack-areas": self.stack_areas,
"stack-to-100": self.stack_to_100,
"area-separator-lines": self.area_separator_lines,
"area-separator-color": self.area_separator_color,
# Customize specific layers
"color-category": ColorCategory.serialize(self.color_category),
# Labels
"show-color-key": self.show_color_key,
# Tooltips
"show-tooltips": self.show_tooltips,
"tooltip-x-format": self.tooltip_x_format,
"tooltip-number-format": self.tooltip_number_format,
# Appearance
**PlotHeight.serialize(
self.plot_height_mode,
self.plot_height_fixed,
self.plot_height_ratio,
),
# Annotations
"text-annotations": ModelListSerializer.serialize(
self.text_annotations, TextAnnotation
),
"range-annotations": ModelListSerializer.serialize(
self.range_annotations, RangeAnnotation
),
}
)
visualize_data = {
# Horizontal and vertical axis (from mixins)
**self._serialize_grid_config(),
**self._serialize_grid_format(),
**self._serialize_custom_range(),
**self._serialize_custom_ticks(),
# Vertical axis (chart-specific)
"y-grid-labels": self.y_grid_labels,
"y-grid-label-align": self.y_grid_label_align,
# Customize areas
"area-opacity": self.area_opacity,
"base-color": self.base_color,
"interpolation": self.interpolation,
"sort-areas": self.sort_areas,
"stack-areas": self.stack_areas,
"stack-to-100": self.stack_to_100,
"area-separator-lines": self.area_separator_lines,
"area-separator-color": self.area_separator_color,
# Customize specific layers
"color-category": ColorCategory.serialize(self.color_category),
# Labels
"show-color-key": self.show_color_key,
# Tooltips
"show-tooltips": self.show_tooltips,
"tooltip-x-format": self.tooltip_x_format,
"tooltip-number-format": self.tooltip_number_format,
# Appearance
**PlotHeight.serialize(
self.plot_height_mode,
self.plot_height_fixed,
self.plot_height_ratio,
),
# Annotations
"text-annotations": ModelListSerializer.serialize(
self.text_annotations, TextAnnotation
),
"range-annotations": ModelListSerializer.serialize(
self.range_annotations, RangeAnnotation
),
}

model["metadata"]["visualize"].update(visualize_data)

# Return the serialized data
return model
Expand All @@ -380,30 +317,13 @@ def deserialize_model(cls, api_response: dict[str, Any]) -> dict[str, Any]:
metadata = api_response.get("metadata", {})
visualize = metadata.get("visualize", {})

# Horizontal axis (X-axis)
init_data["custom_range_x"] = CustomRange.deserialize(
visualize.get("custom-range-x")
)
init_data["custom_ticks_x"] = CustomTicks.deserialize(
visualize.get("custom-ticks-x", "")
)
if "x-grid-format" in visualize:
init_data["x_grid_format"] = visualize["x-grid-format"]
if "x-grid" in visualize:
init_data["x_grid"] = visualize["x-grid"]

# Vertical axis (Y-axis)
init_data["custom_range_y"] = CustomRange.deserialize(
visualize.get("custom-range-y")
)
init_data["custom_ticks_y"] = CustomTicks.deserialize(
visualize.get("custom-ticks-y", "")
)
# Horizontal and vertical axis (from mixins)
init_data.update(cls._deserialize_grid_config(visualize))
init_data.update(cls._deserialize_grid_format(visualize))
init_data.update(cls._deserialize_custom_range(visualize))
init_data.update(cls._deserialize_custom_ticks(visualize))

if "y-grid-format" in visualize:
init_data["y_grid_format"] = visualize["y-grid-format"]
if "y-grid" in visualize:
init_data["y_grid"] = visualize["y-grid"]
# Vertical axis (chart-specific)
if "y-grid-labels" in visualize:
init_data["y_grid_labels"] = visualize["y-grid-labels"]
if "y-grid-label-align" in visualize:
Expand Down
Loading
Loading