Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove unneccessary dashboard dependencies #198

Merged
merged 10 commits into from
Jan 8, 2025
6 changes: 2 additions & 4 deletions docs/source/user_guide/importing_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ A cell object can be created by providing an info dictionary as a keyword argume
# Create a cell object
cell = pyprobe.Cell(info = info_dictionary)

The ``info`` dictionary can contain any number of key-value pairs. The only required key is
``'Name'``, which is used to identify the cell in plots. PyProBE will verify that the
``info`` dictionary contains the ``'Name'`` field. If it does not, it will fill this field with
``'Default Name'``.
The ``info`` dictionary can contain any number of key-value pairs that provide
metadata to identify the cell and the conditions it was tested under.

Converting data to PyProBE Format
---------------------------------
Expand Down
49 changes: 3 additions & 46 deletions pyprobe/cell.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
import zipfile
from typing import Any, Callable, Dict, List, Literal, Optional

import distinctipy
import polars as pl
from pydantic import BaseModel, Field, field_validator, validate_call
from pydantic import BaseModel, Field, validate_call

from pyprobe._version import __version__
from pyprobe.cyclers import arbin, basecycler, basytec, biologic, maccor, neware
Expand All @@ -24,45 +23,14 @@
class Cell(BaseModel):
"""A class for a cell in a battery experiment."""

info: Dict[str, Optional[str | int | float | Dict[Any, Any]]]
info: dict[str, Optional[Any]]
"""Dictionary containing information about the cell.
The dictionary must contain a 'Name' field, other information may include
channel number or other rig information.
"""
procedure: Dict[str, Procedure] = Field(default_factory=dict)
"""Dictionary containing the procedures that have been run on the cell."""

@field_validator("info")
def check_and_set_name(
cls, info: Dict[str, Optional[str | int | float | Dict[Any, Any]]]
) -> Dict[str, Optional[str | int | float | Dict[Any, Any]]]:
"""Validate the `info` field.

Checks that a `Name` field is present in the `info` dictionary, if not it is
set to 'Default Name'. If the `color` field is not present, a color is
generated.
"""
if "Name" not in info.keys():
info["Name"] = "Default Name"
warnings.warn(
"The 'Name' field was not in info. It has been set to 'Default Name'."
)

if "color" not in info.keys():
info["color"] = distinctipy.get_hex(
distinctipy.get_colors(
1,
rng=1, # Set the random seed
exclude_colors=[
(0, 0, 0),
(1, 1, 1),
(1, 1, 0),
],
)[0]
)
values = info
return values

def _convert_to_parquet(
self,
cycler: Literal[
Expand Down Expand Up @@ -396,7 +364,7 @@ def _write_parquet(

@staticmethod
def _get_filename(
info: Dict[str, Optional[str | int | float | Dict[Any, Any]]],
info: Dict[str, Optional[Any]],
filename_function: Callable[[str], str],
filename_inputs: List[str],
) -> str:
Expand Down Expand Up @@ -696,18 +664,7 @@ def make_cell_list(

n_cells = len(record)
cell_list = []
rgb = distinctipy.get_colors(
n_cells,
exclude_colors=[
(0, 0, 0),
(1, 1, 1),
(1, 1, 0),
], # Exclude black, white, and yellow
rng=1, # Set the random seed
n_attempts=5000,
)
for i in range(n_cells):
info = record.row(i, named=True)
info["color"] = distinctipy.get_hex(rgb[i])
cell_list.append(Cell(info=info))
return cell_list
19 changes: 13 additions & 6 deletions pyprobe/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import plotly
import polars as pl
import streamlit as st
from ordered_set import OrderedSet

from pyprobe.cell import Cell
from pyprobe.plot import Plot
Expand Down Expand Up @@ -95,11 +94,10 @@ def dataframe_with_selections(df: pl.DataFrame) -> List[int]:

# Display the DataFrame in the sidebar
selected_indices = dataframe_with_selections(info)
# Get the names of the selected rows
selected_names = [cell_list[i].info["Name"] for i in selected_indices]

# Get the procedure names from the selected cells
procedure_names_sets = [
OrderedSet(cell_list[i].procedure.keys()) for i in selected_indices
list(cell_list[i].procedure.keys()) for i in selected_indices
]

# Find the common procedure names
Expand Down Expand Up @@ -146,7 +144,7 @@ def dataframe_with_selections(df: pl.DataFrame) -> List[int]:

graph_placeholder = st.empty()

col1, col2, col3, col4 = st.columns(4)
col1, col2, col3, col4, col5 = st.columns(5)
# Create select boxes for the x and y axes
filter_stage = col1.selectbox(
"Filter stage", ["", "Experiment", "Cycle", "Step"], index=0
Expand All @@ -155,6 +153,9 @@ def dataframe_with_selections(df: pl.DataFrame) -> List[int]:
x_axis = f"{filter_stage} {x_axis}".strip()
y_axis = col3.selectbox("y axis", y_options, index=1)
secondary_y_axis = col4.selectbox("Secondary y axis", ["None"] + y_options, index=0)
# choose a cell identifier
cell_identifier = col5.selectbox("Legend label", info.collect_schema().names())
selected_names = [cell_list[i].info[cell_identifier] for i in selected_indices]

# Select plot theme

Expand Down Expand Up @@ -188,7 +189,13 @@ def dataframe_with_selections(df: pl.DataFrame) -> List[int]:
if secondary_y_axis == "None":
secondary_y_axis = None

fig = fig.add_line(filtered_data, x_axis, y_axis, secondary_y=secondary_y_axis)
fig = fig.add_line(
filtered_data,
x_axis,
y_axis,
secondary_y=secondary_y_axis,
label=cell_list[selected_index].info[cell_identifier],
)
filtered_data = filtered_data.data.to_pandas()
selected_data.append(filtered_data)

Expand Down
5 changes: 0 additions & 5 deletions pyprobe/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,6 @@ def add_line(
dash (str): The dash style of the line. E.g. "dash", "dot", "dashdot".
showlegend (bool): Whether to show the legend.
"""
if color is None:
if "color" in result.info:
color = str(result.info["color"])
else:
color = "blue"
if label is None:
if "Name" in result.info:
label = str(result.info["Name"])
Expand Down
4 changes: 2 additions & 2 deletions pyprobe/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class Config:

base_dataframe: Union[pl.LazyFrame, pl.DataFrame]
"""The data as a polars DataFrame or LazyFrame."""
info: Dict[str, Optional[str | int | float | Dict[Any, Any]]]
info: dict[str, Optional[Any]]
"""Dictionary containing information about the cell."""
column_definitions: Dict[str, str] = Field(default_factory=dict)
"""A dictionary containing the definitions of the columns in the data."""
Expand Down Expand Up @@ -566,7 +566,7 @@ def build(
| Dict[str, NDArray[np.float64] | List[float]]
]
],
info: Dict[str, Optional[str | int | float | Dict[Any, Any]]],
info: Dict[str, Optional[Any]],
) -> "Result":
"""Build a Result object from a list of dataframes.

Expand Down
2 changes: 0 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ requires-python = ">=3.11,<3.13"
license = { file = "LICENSE" }
dependencies = [
"deprecated>=1.2.15",
"distinctipy>=1.3.4",
"fastexcel>=0.12.0",
"ipykernel>=6.29.5",
"matplotlib>=3.10.0",
"numpy>=2.2.1",
"ordered-set>=4.1.0",
"plotly>=5.24.1",
"polars>=1.18.0",
"pydantic>=2.10.4",
Expand Down
Binary file modified tests/sample_data/neware/Experiment_Record.xlsx
Binary file not shown.
31 changes: 20 additions & 11 deletions tests/test_cell.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Tests for the Cell class."""
import copy
import datetime
import json
import os
import shutil
Expand All @@ -23,25 +24,33 @@ def cell_instance(info_fixture):
def test_init(cell_instance, info_fixture):
"""Test the __init__ method."""
expected_info = copy.copy(info_fixture)
expected_info["color"] = "#ff00ff"
assert cell_instance.info == expected_info
assert cell_instance.procedure == {}

info = {"not name": "test"}
Cell(info=info)
with pytest.warns(UserWarning):
cell = Cell(info=info)
assert cell.info["Name"] == "Default Name"


def test_make_cell_list(info_fixture):
def test_make_cell_list():
"""Test the make_cell_list method."""
filepath = "tests/sample_data/neware/Experiment_Record.xlsx"
record_name = "sample_data_neware"
cell_list = pyprobe.make_cell_list(filepath, record_name)
expected_info = copy.copy(info_fixture)
expected_info["color"] = "#ff00ff"
assert cell_list[0].info == expected_info
assert cell_list[0].info == {
"Name": "Cell1",
"Chemistry": "NMC622",
"Nominal Capacity [Ah]": 5.0,
"Start date": datetime.datetime(2024, 3, 20, 9, 3, 23),
}
assert cell_list[1].info == {
"Name": "Cell2",
"Chemistry": "NMC811",
"Nominal Capacity [Ah]": 3.0,
"Start date": datetime.datetime(2024, 3, 20, 9, 2, 23),
}
assert cell_list[2].info == {
"Name": "Cell3",
"Chemistry": "LFP",
"Nominal Capacity [Ah]": 2.5,
"Start date": datetime.datetime(2024, 3, 20, 9, 3, 23),
}


def test_get_filename(info_fixture):
Expand Down
18 changes: 9 additions & 9 deletions tests/test_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,8 @@ def test_add_line(Plot_fixture, plot_result_fixture):
x = "x"
y = "y"
secondary_y = None
color = None
label = None
color = "blue"
label = "Label"
showlegend = True

Plot_fixture.add_line(
Expand All @@ -284,8 +284,8 @@ def test_add_line(Plot_fixture, plot_result_fixture):
x=result.data[x],
y=result.data[y],
mode="lines",
line=dict(color=result.info["color"], dash="solid"),
name=result.info["Name"],
line=dict(color="blue", dash="solid"),
name="Label",
showlegend=showlegend,
)
assert Plot_fixture._fig.data[0] == expected_trace
Expand All @@ -299,8 +299,8 @@ def test_add_line_with_secondary_y(Plot_fixture, plot_result_fixture):
x = "x"
y = "y"
secondary_y = "secondary_y"
color = None
label = None
color = "blue"
label = "Label"
showlegend = True

Plot_fixture.add_line(
Expand All @@ -319,8 +319,8 @@ def test_add_line_with_secondary_y(Plot_fixture, plot_result_fixture):
x=result.data[x],
y=result.data[y],
mode="lines",
line=dict(color=result.info["color"], dash="solid"),
name=result.info["Name"],
line=dict(color="blue", dash="solid"),
name="Label",
showlegend=showlegend,
)
assert Plot_fixture._fig.data[0] == expected_trace
Expand All @@ -329,7 +329,7 @@ def test_add_line_with_secondary_y(Plot_fixture, plot_result_fixture):
x=result.data[x],
y=result.data[secondary_y],
mode="lines",
line=dict(color=result.info["color"], dash="dash"),
line=dict(color="blue", dash="dash"),
name=result.info["Name"],
yaxis="y2",
showlegend=False,
Expand Down
25 changes: 0 additions & 25 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading