Skip to content

Commit

Permalink
Visual and Data Pivot - read API (#896)
Browse files Browse the repository at this point in the history
* visual edit api

* add data pivot endpoint

* update visual serializer

* update visual test

* rob-barchart slug

* update DataPivotQuery serializer

* add data pivot query api tests

* fix

* updates

* revert change w/ flaky test

* simplify serializer changes?

* change visual.settings  str -> JSON

* update docstring

---------

Co-authored-by: Andy Shapiro <shapiromatron@gmail.com>
  • Loading branch information
caseyhans and shapiromatron authored Sep 22, 2023
1 parent 80508ed commit 104bed1
Show file tree
Hide file tree
Showing 11 changed files with 5,538 additions and 75 deletions.
153 changes: 153 additions & 0 deletions client/hawc_client/summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,74 @@ class SummaryClient(BaseClient):
Client class for summary requests.
"""

def create_visual(self, data: dict) -> dict:
"""Create a new visual
Args:
data (dict): Required metadata for object creation.
- title (str): Visual title
- slug (str): Visual identifier/URL base
- visual_type (int): Constant representing visual type
- published (bool): visual is published for public view
- settings (dict): object settings (must be valid JSON)
- assessment (int): assessment ID
- prefilters (dict): object prefilters (must be valid JSON)
- caption (str): Visual caption
- sort_order (str): how results are sorted
Returns:
dict: The resulting object, if create was successful
"""
url = f"{self.session.root_url}/summary/api/visual/"
return self.session.post(url, data=data).json()

def update_visual(self, visual_id: int, data: dict) -> dict:
"""Create a new visual
Args:
id (int): Visual identifier
data (dict): Metadata to update
- title (str): Visual title
- slug (str): Visual identifier/URL base
- visual_type (int): Constant representing visual type
- published (bool): visual is published for public view
- settings (dict): object settings (must be valid JSON)
- assessment (int): assessment ID
- prefilters (dict): object prefilters (must be valid JSON)
- caption (str): Visual caption
- sort_order (str): how results are sorted
Returns:
dict: The resulting object, if create was successful
"""
url = f"{self.session.root_url}/summary/api/visual/{visual_id}/"
return self.session.patch(url, data=data).json()

def delete_visual(self, visual_id: int):
"""Delete a visual.
Args:
visual_id (int): ID of the visual to delete
Returns:
None: If the operation is successful there is no return value.
If the operation is unsuccessful, an error will be raised.
"""
url = f"{self.session.root_url}/summary/api/visual/{visual_id}/"
self.session.delete(url)

def get_visual(self, visual_id: int):
"""Get a visual.
Args:
visual_id (int): ID of the visual to read
Returns:
dict: The result object, if get was successful
"""
url = f"{self.session.root_url}/summary/api/visual/{visual_id}/"
return self.session.get(url)

def visual_list(self, assessment_id: int) -> pd.DataFrame:
"""
Retrieves a visual list for the given assessment.
Expand All @@ -22,6 +90,91 @@ def visual_list(self, assessment_id: int) -> pd.DataFrame:
response_json = self.session.get(url).json()
return pd.DataFrame(response_json)

def create_datapivot(self, data: dict) -> dict:
"""Create a new data pivot (query)
Args:
data (dict): Required metadata for object creation.
- title (str): Visual title
- slug (str): Visual identifier/URL base
- evidence_type (int): Constant representing type of evidence used in data pivot
(see hawc.apps.study.constants.StudyType)
- export_style (int): Constant representing how the level at which data are aggregated,
and therefore which columns and types of data are presented in the export, for use
in the visual (see hawc.apps.summary.constants.ExportStyle)
- preferred_units: List of preferred dose-values IDs, in order of preference.
If empty, dose-units will be random for each endpoint
presented. This setting may used for comparing
percent-response, where dose-units are not needed, or for
creating one plot similar, but not identical, dose-units.
- published (bool): datapivot is published for public view
- settings (str): JSON of object settings
- assessment (int): assessment ID
- prefilters (str): JSON of object prefilters
- caption (str): Data pivot caption
Returns:
dict: The resulting object, if create was successful
"""
url = f"{self.session.root_url}/summary/api/data_pivot_query/"
return self.session.post(url, data=data).json()

def update_datapivot(self, datapivot_id: int, data: dict) -> dict:
"""Update an existing data pivot (query)
Args:
id (int): Data pivot identifier
data (dict): Required metadata for object creation.
- title (str): Visual title
- slug (str): Visual identifier/URL base
- evidence_type (int): Constant representing type of evidence used in data pivot
(see hawc.apps.study.constants.StudyType)
- export_style (int): Constant representing how the level at which data are aggregated,
and therefore which columns and types of data are presented in the export, for use
in the visual (see hawc.apps.summary.constants.ExportStyle)
- preferred_units: List of preferred dose-values IDs, in order of preference.
If empty, dose-units will be random for each endpoint
presented. This setting may used for comparing
percent-response, where dose-units are not needed, or for
creating one plot similar, but not identical, dose-units.
- published (bool): datapivot is published for public view
- settings (str): JSON of object settings
- assessment (int): assessment ID
- prefilters (str): JSON of object prefilters
- caption (str): Data pivot caption
Returns:
dict: The resulting object, if update was successful
"""
url = f"{self.session.root_url}/summary/api/data_pivot_query/{datapivot_id}/"
return self.session.patch(url, data=data).json()

def get_datapivot(self, datapivot_id: int):
"""Get a data pivot (query).
Args:
visual_id (int): ID of the visual to read
Returns:
dict: object, if successful
"""
url = f"{self.session.root_url}/summary/api/data_pivot_query/{datapivot_id}/"
return self.session.get(url)

def delete_datapivot(self, datapivot_id: int):
"""Delete a data pivot (query).
Args:
visual_id (int): ID of the visual to delete
Returns:
None: If the operation is successful there is no return value.
If the operation is unsuccessful, an error will be raised.
"""
url = f"{self.session.root_url}/summary/api/data_pivot_query/{datapivot_id}/"
self.session.delete(url)

def datapivot_list(self, assessment_id: int) -> pd.DataFrame:
"""
Retrieves a data pivot list for the given assessment.
Expand Down
11 changes: 10 additions & 1 deletion hawc/apps/summary/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,23 @@ def data(self, request, pk):
return Response(export)


class VisualViewSet(AssessmentViewSet):
class DataPivotQueryViewSet(EditPermissionsCheckMixin, AssessmentEditViewSet):
edit_check_keys = ["assessment"]
assessment_filter_args = "assessment"
model = models.DataPivotQuery
filter_backends = (InAssessmentFilter, UnpublishedFilter)
serializer_class = serializers.DataPivotQuerySerializer


class VisualViewSet(EditPermissionsCheckMixin, AssessmentEditViewSet):
"""
For list view, return all Visual objects for an assessment, but using the
simplified collection view.
For all other views, use the detailed visual view.
"""

edit_check_keys = ["assessment"]
assessment_filter_args = "assessment"
model = models.Visual
pagination_class = DisabledPagination
Expand Down
26 changes: 20 additions & 6 deletions hawc/apps/summary/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,30 @@ class Meta:


class DataPivotSerializer(serializers.ModelSerializer):
url = serializers.CharField(source="get_absolute_url")
data_url = serializers.CharField(source="get_data_url")
download_url = serializers.CharField(source="get_download_url")
visual_type = serializers.CharField(source="get_visual_type_display")
url = serializers.CharField(source="get_absolute_url", read_only=True)
data_url = serializers.CharField(source="get_data_url", read_only=True)
download_url = serializers.CharField(source="get_download_url", read_only=True)

def to_representation(self, instance):
ret = super().to_representation(instance)
ret["visual_type"] = instance.get_visual_type_display()
return ret

class Meta:
model = models.DataPivot
fields = "__all__"


class DataPivotQuerySerializer(DataPivotSerializer):
preferred_units = serializers.ListField(
allow_empty=True, child=serializers.IntegerField(min_value=0)
)

class Meta:
model = models.DataPivotQuery
fields = "__all__"


class CollectionVisualSerializer(serializers.ModelSerializer):
url = serializers.CharField(source="get_absolute_url")
visual_type = serializers.CharField(source="get_visual_type_display")
Expand All @@ -39,8 +53,6 @@ class Meta:


class VisualSerializer(serializers.ModelSerializer):
visual_type = serializers.CharField(source="get_visual_type_display")

def to_representation(self, instance):
ret = super().to_representation(instance)

Expand All @@ -56,6 +68,8 @@ def to_representation(self, instance):
]:
ret["rob_settings"] = AssessmentRiskOfBiasSerializer(instance.assessment).data

ret["visual_type"] = instance.get_visual_type_display()

ret["endpoints"] = [
SerializerHelper.get_serialized(d, json=False) for d in instance.get_endpoints()
]
Expand Down
1 change: 1 addition & 0 deletions hawc/apps/summary/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
router.register(r"assessment", api.SummaryAssessmentViewSet, basename="assessment")
router.register(r"visual", api.VisualViewSet, basename="visual")
router.register(r"data_pivot", api.DataPivotViewSet, basename="data_pivot")
router.register(r"data_pivot_query", api.DataPivotQueryViewSet, basename="data_pivot_query")
router.register(r"summary-text", api.SummaryTextViewSet, basename="summary-text")
router.register(r"summary-table", api.SummaryTableViewSet, basename="summary-table")

Expand Down
Loading

0 comments on commit 104bed1

Please sign in to comment.