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
20 changes: 20 additions & 0 deletions Backend/postgres_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -656,5 +656,25 @@ def build_family_where_text(self, filters):
# Single value
conditions.append(f'degree = {int(values)}')

elif fil == 'dimension':
# families_dim_1_nf only contains dimension 1 objects
dims = values if isinstance(values, list) else [values]
dims = [int(d) for d in dims]
if 1 not in dims:
# Requested dimension is not present in this table
conditions.append('1 = 0')

elif fil == 'is_polynomial':
# Same style as system filter: IN (...)
conditions.append(
'is_polynomial IN (' + ', '.join(str(v) for v in values) + ')'
)

elif fil == 'base_field_label':
# Partial match, case-insensitive
conditions.append(
f"base_field_label ILIKE '%' || TRIM('{values}') || '%'"
)

filter_text += ' AND '.join(conditions)
return filter_text
2 changes: 1 addition & 1 deletion Frontend/src/api/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const get_families = () => api.get("/get_all_families");
export const get_family = (familyId) => api.post("/get_family", { id: familyId });

// dreyes: used to filter families based on the filters selected in the UI
export const get_filtered_families = (filtered) => api.post("/get_filtered_familes", filters);
export const get_filtered_families = (filters) => api.post("/get_filtered_families", filters);

export const get_rational_periodic_data = (functionId) =>
api.post("/get_rational_periodic_data", { function_id: functionId });
Expand Down
2 changes: 1 addition & 1 deletion Frontend/src/components/PaginatedDataTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export default function PaginatedDataTable({ labels, data, itemsPerPage, current
<tr key={key} className={key % 2 === 0 ? 'even-row' : 'odd-row'} style={{ textAlign: 'center' }}>
{item.map((element, id) => (
<td key={id}>
<span>{id === 3 ? renderExponent(element) :element}</span>
<span>{id === 3 && typeof element === 'string' ? renderExponent(element) : element}</span>
</td>
))}
</tr>
Expand Down
8 changes: 7 additions & 1 deletion Frontend/src/context/FilterContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ export const FilterProvider = ({ children }) => {
// dreyes: Family page filters
family_id: "",
family_name: "",
family_degree: []
family_degree: [],

//dreyes: added more filters for domain, polynomial, and field labels
family_dimension: [],
family_custom_dimension: "",
family_is_polynomial: [],
family_base_field_label: ""
});

return (
Expand Down
163 changes: 156 additions & 7 deletions Frontend/src/pages/FilteredFamilies.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import Divider from "@mui/material/Divider";
import { useFilters } from '../context/FilterContext';
import { useNavigate } from 'react-router-dom';
import Button from 'react-bootstrap/Button';
import HelpBox from "../components/FunctionDetail/HelpBox"; //dreyes: renders tooltips for labels.
import ActiveFiltersBanner from '../components/ActiveFiltersBanner'; //dreyes: shows active filters above the results table, only renders if there are active filters

// dreyes: this is the new family page, it allows you to filter the families based on the filters on the left
// sidebar, and then shows the results in a table on the right, you can click on the family id to go to the family details page
Expand All @@ -17,16 +19,25 @@ function FilteredFamilies() {
const [pagesPer] = useState('20');
const [page, setPage] = useState(1);
const [triggerFetch, setTriggerFetch] = useState(false);
const [filtersApplied, setFiltersApplied] = useState([]);

// Fetch families with current filters
const fetchFilteredFamilies = async () => {
try {
const result = await get_filtered_families({
const familyFilters = {
family_id: filters.family_id,
name: filters.family_name,
degree: filters.family_degree
});
degree: filters.family_degree,

dimension: filters.family_custom_dimension === ""
? filters.family_dimension
: [...filters.family_dimension, Number(filters.family_custom_dimension)],
is_polynomial: filters.family_is_polynomial,
base_field_label: filters.family_base_field_label
};
const result = await get_filtered_families(familyFilters);
setFamilies(result.data);
setFiltersApplied({ ...familyFilters });
} catch (error) {
console.log(error);
}
Expand Down Expand Up @@ -66,7 +77,11 @@ function FilteredFamilies() {
...filters,
family_id: "",
family_name: "",
family_degree: []
family_degree: [],
family_dimension: [],
family_custom_dimension: "",
family_is_polynomial: [],
family_base_field_label: ""
});
setTriggerFetch(prev => !prev);
setPage(1);
Expand Down Expand Up @@ -96,6 +111,60 @@ function FilteredFamilies() {
marginRight: "12px",
};

const smallStyles = {
inlineHelpLabel: {
fontSize: "0.9rem",
whiteSpace: "nowrap",
display: "inline-block",
verticalAlign: "middle"
}
};

const buildMonomials = (degree) => {
const mon = [];
for (let i = 0; i <= degree; i++) {
if (i === 0) mon.push(`x^${degree}`);
else if (i === degree) mon.push(`y^${degree}`);
else if (degree - i === 1 && i === 1) mon.push("xy");
else if (i === 1) mon.push(`x^${degree - i}y`);
else if (degree - i === 1) mon.push(`xy^${i}`);
else mon.push(`x^${degree - i}y^${i}`);
}
return mon;
};

const formatFamilyPolynomial = (coeffs, degree) => {
if (!Array.isArray(coeffs) || coeffs.length < 2 || !Number.isInteger(Number(degree))) {
return "N/A";
}

const d = Number(degree);
const mon = buildMonomials(d);

const formatOnePoly = (polyCoeffs) => {
if (!Array.isArray(polyCoeffs)) return "N/A";
let out = "";
let firstTerm = true;

for (let i = 0; i <= d && i < polyCoeffs.length; i++) {
const c = String(polyCoeffs[i]);
if (c === "0") continue;

if (!firstTerm && !c.startsWith("-")) out += "+";
if (c === "1") out += mon[i];
else if (c === "-1") out += `-${mon[i]}`;
else out += `${c}${mon[i]}`;
firstTerm = false;
}

return out || "0";
};

const left = formatOnePoly(coeffs[0]);
const right = formatOnePoly(coeffs[1]);
return `[${left} : ${right}]`;
};

return (
<>
<div className="results-container" container>
Expand Down Expand Up @@ -175,6 +244,77 @@ function FilteredFamilies() {
</li>
</ul>

{/* Dimension Filter */}
<ul id="myUL">
<li>
<span className="caret" onClick={toggleTree}>
Dimension
</span>
<ul className="nested">
<input
type="checkbox"
checked={filters.family_dimension.includes(1)}
onChange={() => handleCheckboxChange("family_dimension", 1)}
/>
<label>
P<sup>1</sup> {String.fromCharCode(8594)} P<sup>1</sup>
</label>
<br />
<input
type="checkbox"
checked={filters.family_dimension.includes(2)}
onChange={() => handleCheckboxChange("family_dimension", 2)}
/>
<label>
P<sup>2</sup> {String.fromCharCode(8594)} P<sup>2</sup>
</label>
<br />
<input
type="number"
style={textBoxStyle}
value={filters.family_custom_dimension || ""}
onChange={(e) => handleTextChange("family_custom_dimension", e.target.value)}
/>
<label>Custom</label>
</ul>
</li>
</ul>

{/* Polynomial Type Filter */}
<ul id="myUL">
<li>
<span className="caret" onClick={toggleTree}>
Type
</span>
<ul className="nested">
<input
type="checkbox"
checked={filters.family_is_polynomial.includes(true)}
onChange={() => handleCheckboxChange("family_is_polynomial", true)}
/>
<label>Polynomial</label>
</ul>
</li>
</ul>

{/* Field Label Filter */}
<ul id="myUL">
<li>
<span className="caret" onClick={toggleTree}>
Field of Definition
</span>
<ul className="nested">
<input
type="text"
style={textBoxStyle}
value={filters.family_base_field_label || ""}
onChange={(e) => handleTextChange("family_base_field_label", e.target.value)}
/>
<label>Field</label>
</ul>
</li>
</ul>

<br />
{/* Action Buttons */}
<ul id="myUL">
Expand Down Expand Up @@ -203,11 +343,15 @@ function FilteredFamilies() {

{/* Results Table */}
<Grid className="results-table" item xs={6}>
{filtersApplied && <ActiveFiltersBanner filters={filtersApplied} />}
<PaginatedDataTable
labels={[
"Family Id",
"Family Name",
"Degree",
<><span style={smallStyles.inlineHelpLabel}>Family Id</span><HelpBox description="Unique identifier for a family record in the database." title="Family Id" /></>,
<><span style={smallStyles.inlineHelpLabel}>Family Name</span><HelpBox description="Descriptive name of the family of maps." title="Family Name" /></>,
<><span style={smallStyles.inlineHelpLabel}>Degree</span><HelpBox description="Degree of the representative maps in this family." title="Degree" /></>,
<><span style={smallStyles.inlineHelpLabel}>Domain</span><HelpBox description="The ambient domain of the map; a projective space" title="Domain" /></>,
<><span style={smallStyles.inlineHelpLabel}>Polynomial</span><HelpBox description="Representative polynomials for this family model." title="Polynomials" /></>,
<><span style={smallStyles.inlineHelpLabel}>Field</span><HelpBox description="The field label attached to the family definition." title="Field" /></>
]}
data={
families === null
Expand All @@ -226,6 +370,11 @@ function FilteredFamilies() {
</button>,
x[1],
x[2],
<>
P<sup>1</sup> {String.fromCharCode(8594)} P<sup>1</sup>
</>,
formatFamilyPolynomial(x[4], x[2]),
x[6]
])
}
itemsPerPage={pagesPer}
Expand Down
Loading