Skip to content

Commit

Permalink
finished note scouting app support
Browse files Browse the repository at this point in the history
  • Loading branch information
Shom770 committed Sep 14, 2023
1 parent d0d335e commit b3e35ad
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 54 deletions.
169 changes: 124 additions & 45 deletions falconscoutcore/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,46 +51,96 @@ def _process_data(*data: list[str], status_message_col) -> None:
:param status_message_col: The Streamlit column for displaying status messages.
:return:
"""
data_maps = []
quantitative_data_maps = []
qualitative_data_maps = []

for raw_data in data:
data_labels = CONFIG["data_config"]["data_labels"]
quantitative_data_labels = CONFIG["data_config"]["quantitative_data_labels"]
qualitative_data_labels = CONFIG["data_config"]["qualitative_data_labels"]
split_data = raw_data.split(CONFIG["data_config"]["delimiter"])

if len(split_data) != len(data_labels):
if len(split_data) == len(quantitative_data_labels):
quantitative_data_maps.append(
{
field: _convert_string_to_proper_type(data)
for field, data in zip(quantitative_data_labels, split_data)
}
)
elif len(split_data) == len(qualitative_data_labels):
qualitative_data_maps.append(
{
field: _convert_string_to_proper_type(data)
for field, data in zip(qualitative_data_labels, split_data)
}
)
else:
status_message_col.error(
f"Scanned QR code from {split_data[0]} has {len(split_data)} fields "
f"while Core expected {len(data_labels)} fields."
f"while Core expected {len(quantitative_data_labels)} fields."
f" The scouter is likely using an older version of FalconScout."
)
return

data_maps.append({field: data for field, data in zip(data_labels, split_data)})
if quantitative_data_maps:
with open(CONFIG["data_config"]["json_file"], "r+") as data_file:
scouting_data = load(data_file)
data_maps = [
data_map
for data_map in quantitative_data_maps
if data_map not in scouting_data
]

# If some QR codes were already scanned
if len(data_maps) != len(data):
status_message_col.warning(
f"{len(data) - len(data_maps)} QR code(s) were already scanned.",
icon="🚨",
)

with open(CONFIG["data_config"]["json_file"], "r+") as data_file:
scouting_data = load(data_file)
data_maps = [
data_map for data_map in data_maps if data_map not in scouting_data
]

# If some QR codes were already scanned
if len(data_maps) != len(data):
status_message_col.warning(
f"{len(data) - len(data_maps)} QR code(s) were already scanned.",
icon="🚨",
# If all QR codes were already scanned
if len(data_maps) == 0:
return

scouting_data.extend(data_maps)

data_file.seek(0)
dump(scouting_data, data_file, indent=2)
data_file.truncate()

status_message_col.success(
f"{len(data_maps)} QR code(s) successfully scanned!", icon="✅"
)

# If all QR codes were already scanned
if len(data_maps) == 0:
return
if qualitative_data_maps:
with open(CONFIG["data_config"]["qualitative_json_file"], "r+") as data_file:
scouting_data = load(data_file)
data_maps = [
data_map
for data_map in qualitative_data_maps
if data_map not in scouting_data
]

# If some QR codes were already scanned
if len(data_maps) != len(data):
status_message_col.warning(
f"{len(data) - len(data_maps)} note scouting app QR code(s) were already scanned.",
icon="🚨",
)

# If all QR codes were already scanned
if len(data_maps) == 0:
return

scouting_data.extend(data_maps)
scouting_data.extend(data_maps)

data_file.seek(0)
dump(scouting_data, data_file, indent=2)
data_file.truncate()
data_file.seek(0)
dump(scouting_data, data_file, indent=2)
data_file.truncate()

status_message_col.success(f"{len(data_maps)} QR code(s) successfully scanned!", icon="✅")
status_message_col.success(
f"{len(data_maps)} note scouting app QR code(s) successfully scanned!",
icon="✅",
)


# Main functions
Expand All @@ -114,23 +164,23 @@ def scan_qrcode(qr_code_col) -> None:
if qr_codes:
_process_data(
*[qr_code.data.decode("utf-8") for qr_code in qr_codes],
status_message_col=qr_code_col
status_message_col=qr_code_col,
)


def write_dataval_errors(data_val_col) -> None:
"""Writes the data validation errors contained in `errors.json` into the column."""
with (
open(CONFIG["data_config"]["error_json"]) as error_file,
open("./streamlit_components/error_component.html", "r") as component_file
open("./streamlit_components/error_component.html", "r") as component_file,
):
scouting_data_errors = load(error_file)
error_component = component_file.read()

errors_by_match = sorted(
scouting_data_errors,
key=lambda error: int(error["match"][2:]),
reverse=True
reverse=True,
)

with data_val_col:
Expand All @@ -140,9 +190,9 @@ def write_dataval_errors(data_val_col) -> None:
error_title=error["message"],
error_type=error["error_type"],
match_key=error["match"],
height="150px"
height="150px",
),
height=150
height=150,
)


Expand All @@ -154,38 +204,35 @@ def run_dataval(success_col) -> None:
data_validator = DataValidation2023("./data_validation/config.yaml")

with open(CONFIG["data_config"]["json_file"]) as scouting_data_file:
data_validator.validate_data(
load(scouting_data_file)
)
data_validator.validate_data(load(scouting_data_file))

# Read how many errors were raised for the status message.
with open(CONFIG["data_config"]["error_json"]) as error_file:
amount_of_errors = len(load(error_file))

if amount_of_errors > 0:
success_col.warning(
f"{amount_of_errors} errors were raised when validating the data.",
icon="🚨"
f"{amount_of_errors} errors were raised when validating the data.", icon="🚨"
)
else:
success_col.success(
"No errors were raised when validating the data!",
icon="✅"
)
success_col.success("No errors were raised when validating the data!", icon="✅")


def sync_to_github(success_col) -> None:
"""Syncs the current scouting data JSON and CSV to GitHub with their respective files.
:param success_col: The column to write success messages into.
"""
with open(CONFIG["data_config"]["json_file"]) as file:
with (
open(CONFIG["data_config"]["json_file"]) as file,
open(CONFIG["data_config"]["qualitative_json_file"]) as qualitative_file,
):
file_json_data = load(file)
qualitative_json_data = load(qualitative_file)

file_csv_data = pd.read_csv(
CONFIG["data_config"].get(
"csv_file",
CONFIG["data_config"]["json_file"].replace("json", "csv")
"csv_file", CONFIG["data_config"]["json_file"].replace("json", "csv")
)
)

Expand All @@ -198,6 +245,14 @@ def sync_to_github(success_col) -> None:
contents.sha,
)

contents = repo.get_contents(CONFIG["repo_config"]["update_qualitative_json"])
repo.update_file(
contents.path,
f'updated data @ {datetime.datetime.now().strftime("%m/%d/%Y, %H:%M:%S")}',
str(qualitative_json_data),
contents.sha,
)

contents = repo.get_contents(CONFIG["repo_config"]["update_csv"])
repo.update_file(
contents.path,
Expand All @@ -211,22 +266,46 @@ def sync_to_github(success_col) -> None:

def display_data() -> None:
"""Displays the scouting data in a table format that can be edited and is paginated."""
with open(CONFIG["data_config"]["json_file"]) as data_file:
with (
open(CONFIG["data_config"]["json_file"]) as data_file,
open(CONFIG["data_config"]["qualitative_json_file"]) as qualitative_data_file,
):
scouting_data = load(data_file)
note_scouting_data = load(qualitative_data_file)

scouting_df = pd.DataFrame.from_dict(scouting_data)
note_scouting_df = pd.DataFrame.from_dict(note_scouting_data)

data_display_col, status_message_col = st.columns([1.5, 1], gap="medium")

data_display_col.write("### 📊 Scouting Data Editor")
status_message_col.write("### ✅ Status Messages")

# Quantitative scouting data editor
resultant_df = data_display_col.data_editor(scouting_df, num_rows="dynamic")

# Qualitative scouting data editor
data_display_col.write("### 📝 Note Scouting Data Editor")
resultant_quali_df = data_display_col.data_editor(
note_scouting_df, num_rows="dynamic"
)

# Check if the data changed
if not scouting_df[~scouting_df.apply(tuple, 1).isin(resultant_df.apply(tuple, 1))].empty:
status_message_col.success("Data changed successfully!", icon="✅")
if not scouting_df[
~scouting_df.apply(tuple, 1).isin(resultant_df.apply(tuple, 1))
].empty:
status_message_col.success("Scouting data changed successfully!", icon="✅")
resultant_df.to_json(
CONFIG["data_config"]["json_file"], orient="records", indent=2
)

resultant_df.to_json(CONFIG["data_config"]["json_file"], orient="records", indent=2)
if not note_scouting_df[
~note_scouting_df.apply(tuple, 1).isin(resultant_quali_df.apply(tuple, 1))
].empty:
status_message_col.success("Note scouting data changed successfully!", icon="✅")
resultant_quali_df.to_json(
CONFIG["data_config"]["qualitative_json_file"], orient="records", indent=2
)


if __name__ == "__main__":
Expand Down
35 changes: 28 additions & 7 deletions falconscoutcore/config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"data_config": {
"delimiter": "|",
"data_labels": [
"quantitative_data_labels": [
"ScoutId",
"MatchKey",
"Alliance",
Expand All @@ -28,17 +28,38 @@
"DriverRating",
"RatingNotes"
],
"data_types": [
"string",
"string",
"string",
"int"
"qualitative_data_labels": [
"ScoutId",
"MatchKey",
"Alliance",
"DriverStation",
"TeamNumber",
"AutoPieces",
"AutoStartingPosition",
"AutoEngaged",
"AutoIntakeAccuracy",
"AutoScoringAccuracy",
"AutoDrivingSkills",
"AutoNotes",
"TeleopPieces",
"TeleopPath",
"TeleopAligningSpeed",
"TeleopCommunitySkill",
"TeleopIntakingLocation",
"Disabled",
"Tippy",
"DriverRating",
"ConeIntakingSkill",
"CubeIntakingSkill",
"SubstationSpeed"
],
"json_file": "./data/2023new_match_data.json",
"qualitative_json_file": "./data/2023new_qualitative_data.json",
"error_json": "./data/errors.json"
},
"repo_config": {
"repo": "team4099/ScoutingAppData",
"update_json": "2023new_match_data.json"
"update_json": "2023new_match_data.json",
"update_qualitative_json": "2023new_qualitative_data.json"
}
}
4 changes: 2 additions & 2 deletions falconscoutcore/data/2023new_match_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -1998,7 +1998,7 @@
"ScoutId":"Nikhil",
"MatchKey":"qm107",
"Alliance":"blue",
"DriverStation":1,
"DriverStation":2,
"TeamNumber":6431,
"Preloaded":"true",
"AutoGrid":"None",
Expand Down Expand Up @@ -23169,4 +23169,4 @@
"SuccessfulTripleBalance":0,
"uuid":"bceeb963-f6ea-4a86-aa7d-5065b88a7e65"
}
]
]
27 changes: 27 additions & 0 deletions falconscoutcore/data/2023new_qualitative_data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[
{
"ScoutId":"shayaan",
"MatchKey":"qm,1",
"Alliance":"red",
"DriverStation":"1",
"TeamNumber":4099.0,
"AutoPieces":2.0,
"AutoStartingPosition":"Cable protector side",
"AutoEngaged":"true",
"AutoIntakeAccuracy":"false",
"AutoScoringAccuracy":"Great",
"AutoDrivingSkills":"true",
"AutoNotes":"",
"TeleopPieces":2.0,
"TeleopPath":"Cable protector side to loading zone",
"TeleopAligningSpeed":"Slow",
"TeleopCommunitySkill":"Smoothly",
"TeleopIntakingLocation":"Ground",
"Disabled":"true",
"Tippy":"true",
"DriverRating":"Fluid",
"ConeIntakingSkill":"Very Good",
"CubeIntakingSkill":"Good",
"SubstationSpeed":"Poor"
}
]

0 comments on commit b3e35ad

Please sign in to comment.