Package com.studentgui.apppages
Class JLineGraph
java.lang.Object
java.awt.Component
java.awt.Container
javax.swing.JComponent
javax.swing.JPanel
com.studentgui.apppages.JLineGraph
- All Implemented Interfaces:
SettingsChangeListener,ImageObserver,MenuContainer,Serializable,Accessible
Reusable JFreeChart-based line chart component for visualizing student assessment progress.
This component is shared across all assessment pages (Braille, Abacus, iOS, ScreenReader, etc.) to display time-series data showing skill progression over multiple sessions. It supports three primary visualization modes:
- Single-chart mode:
updateWithData(java.util.List)- Plots all skills on one chart with historical sessions in gray and the latest session highlighted in black - Grouped mode (session indices):
updateWithGroupedData(java.util.List, String[])- Creates multiple stacked charts, one per phase group (determined by part code prefix like "P1", "P2") - Grouped mode (chronological dates):
updateWithGroupedDataByDate(java.util.List, java.util.List, String[], String[])- Plots grouped data with actual dates on the X-axis for true time-series visualization
Visual Design and Rendering:
- Background bands: Colored horizontal bands indicate score ranges to aid interpretation:
- Red band: -0.25 to 0.5 (minimal/no proficiency)
- Orange bands: 0.5–1.5, 1.5–2.5 (emerging skills)
- Yellow band: 2.5–3.5 (developing proficiency)
- Green band: 3.5–4.5 (mastery/proficient)
- Rendering jitter: A configurable visual jitter of ±0.1 is applied
to plotted points via
addJitter(double)to reveal overlapping data points. This is a display-only transformation and does not modify persisted values. Jitter can be:- Enabled/disabled via
setJitterEnabled(boolean) - Made deterministic (for testing) via
setJitterDeterministic(boolean)andsetJitterSeed(Long) - Configured via
Settingskeys: "jitter.enabled", "jitter.deterministic", "jitter.seed"
- Enabled/disabled via
- Color palette: Consistent color-blind friendly palette used for series rendering:
PALETTE_HEX: Hex color strings for HTML legend generation (8 colors)PALETTE: AWT Color objects for JFreeChart rendering (8 colors matching PALETTE_HEX)
Typical Workflow for Assessment Pages:
- Page fetches recent sessions from database via
Database.fetchLatestAssessmentResultsWithDates(java.lang.String, java.lang.String, int) - Page calls
updateWithGroupedDataByDate(java.util.List, java.util.List, String[], String[])to populate chart - On submit, page calls
saveGroupedCharts(java.nio.file.Path, String, int, int)to export PNG images - Page generates Markdown/HTML reports linking to the exported plots
Export and Persistence:
saveGroupedCharts(java.nio.file.Path, String, int, int)- Exports each phase group as a separate PNG filesaveChart(java.nio.file.Path, int, int)- Exports the single main chart (when not in grouped mode)- Returns Map<groupName, filePath> for use in report generation
Accessibility:
- ChartPanel accessible name set to "Skill progression chart"
- Tooltips enabled showing coordinate values on hover
- Keyboard navigation supported through JFreeChart's default ChartPanel behavior
Settings Integration: Implements SettingsChangeListener to respond
to jitter configuration changes at runtime without requiring application restart.
- See Also:
-
Nested Class Summary
Nested classes/interfaces inherited from class javax.swing.JPanel
JPanel.AccessibleJPanelNested classes/interfaces inherited from class javax.swing.JComponent
JComponent.AccessibleJComponentNested classes/interfaces inherited from class java.awt.Container
Container.AccessibleAWTContainerNested classes/interfaces inherited from class java.awt.Component
Component.AccessibleAWTComponent, Component.BaselineResizeBehavior, Component.BltBufferStrategy, Component.FlipBufferStrategy -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final Color[]Public color palette as AWT Color objects for chart rendering.static final String[]Public color palette (hex) for HTML legends and consistency across pages.Fields inherited from class javax.swing.JComponent
listenerList, TOOL_TIP_TEXT_KEY, ui, UNDEFINED_CONDITION, WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, WHEN_FOCUSED, WHEN_IN_FOCUSED_WINDOWFields inherited from class java.awt.Component
accessibleContext, BOTTOM_ALIGNMENT, CENTER_ALIGNMENT, LEFT_ALIGNMENT, RIGHT_ALIGNMENT, TOP_ALIGNMENTFields inherited from interface java.awt.image.ImageObserver
ABORT, ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, WIDTH -
Constructor Summary
ConstructorsConstructorDescriptionCreate a new JLineGraph with default styling and an empty dataset. -
Method Summary
Modifier and TypeMethodDescriptionReturn the currently configured jitter seed or null when unset.booleanQuery whether deterministic jitter is enabled.booleanQuery whether rendering jitter is currently enabled.voidSave the current chart to a PNG file.saveGroupedCharts(Path dir, String baseName, int width, int heightPerGroup) Save each grouped subchart as an individual PNG file.voidsetJitterDeterministic(boolean deterministic) Enable/disable deterministic (seeded) jitter.voidsetJitterEnabled(boolean enabled) Enable or disable rendering jitter at runtime.voidsetJitterSeed(Long seed) Set the seed used when deterministic jitter is enabled.voidInvoked when application settings have been changed and persisted.voidshowEmptyGrouped(String[] partCodes) Show an empty grouped chart using the provided part codes.voidupdateWithData(List<List<Integer>> allSkillValues) Replace the current dataset with the provided list of skill value series.voidupdateWithGroupedData(List<List<Integer>> allSkillValues, String[] partCodes) Update the component with grouped plots.voidPlot grouped data over time.voidupdateWithGroupedDataByDate(List<LocalDate> dates, List<List<Integer>> rows, String[] partCodes, String[] partLabels) Plot grouped data over time with optional human-friendly labels.Methods inherited from class javax.swing.JPanel
getAccessibleContext, getUI, getUIClassID, paramString, setUI, updateUIMethods inherited from class javax.swing.JComponent
addAncestorListener, addNotify, addVetoableChangeListener, computeVisibleRect, contains, createToolTip, disable, enable, firePropertyChange, firePropertyChange, firePropertyChange, fireVetoableChange, getActionForKeyStroke, getActionMap, getAlignmentX, getAlignmentY, getAncestorListeners, getAutoscrolls, getBaseline, getBaselineResizeBehavior, getBorder, getBounds, getClientProperty, getComponentGraphics, getComponentPopupMenu, getConditionForKeyStroke, getDebugGraphicsOptions, getDefaultLocale, getFontMetrics, getGraphics, getHeight, getInheritsPopupMenu, getInputMap, getInputMap, getInputVerifier, getInsets, getInsets, getListeners, getLocation, getMaximumSize, getMinimumSize, getNextFocusableComponent, getPopupLocation, getPreferredSize, getRegisteredKeyStrokes, getRootPane, getSize, getToolTipLocation, getToolTipText, getToolTipText, getTopLevelAncestor, getTransferHandler, getVerifyInputWhenFocusTarget, getVetoableChangeListeners, getVisibleRect, getWidth, getX, getY, grabFocus, hide, isDoubleBuffered, isLightweightComponent, isManagingFocus, isOpaque, isOptimizedDrawingEnabled, isPaintingForPrint, isPaintingOrigin, isPaintingTile, isRequestFocusEnabled, isValidateRoot, paint, paintBorder, paintChildren, paintComponent, paintImmediately, paintImmediately, print, printAll, printBorder, printChildren, printComponent, processComponentKeyEvent, processKeyBinding, processKeyEvent, processMouseEvent, processMouseMotionEvent, putClientProperty, registerKeyboardAction, registerKeyboardAction, removeAncestorListener, removeNotify, removeVetoableChangeListener, repaint, repaint, requestDefaultFocus, requestFocus, requestFocus, requestFocusInWindow, requestFocusInWindow, resetKeyboardActions, reshape, revalidate, scrollRectToVisible, setActionMap, setAlignmentX, setAlignmentY, setAutoscrolls, setBackground, setBorder, setComponentPopupMenu, setDebugGraphicsOptions, setDefaultLocale, setDoubleBuffered, setEnabled, setFocusTraversalKeys, setFont, setForeground, setInheritsPopupMenu, setInputMap, setInputVerifier, setMaximumSize, setMinimumSize, setNextFocusableComponent, setOpaque, setPreferredSize, setRequestFocusEnabled, setToolTipText, setTransferHandler, setUI, setVerifyInputWhenFocusTarget, setVisible, unregisterKeyboardAction, updateMethods inherited from class java.awt.Container
add, add, add, add, add, addContainerListener, addImpl, addPropertyChangeListener, addPropertyChangeListener, applyComponentOrientation, areFocusTraversalKeysSet, countComponents, deliverEvent, doLayout, findComponentAt, findComponentAt, getComponent, getComponentAt, getComponentAt, getComponentCount, getComponents, getComponentZOrder, getContainerListeners, getFocusTraversalKeys, getFocusTraversalPolicy, getLayout, getMousePosition, insets, invalidate, isAncestorOf, isFocusCycleRoot, isFocusCycleRoot, isFocusTraversalPolicyProvider, isFocusTraversalPolicySet, layout, list, list, locate, minimumSize, paintComponents, preferredSize, printComponents, processContainerEvent, processEvent, remove, remove, removeAll, removeContainerListener, setComponentZOrder, setFocusCycleRoot, setFocusTraversalPolicy, setFocusTraversalPolicyProvider, setLayout, transferFocusDownCycle, validate, validateTreeMethods inherited from class java.awt.Component
action, add, addComponentListener, addFocusListener, addHierarchyBoundsListener, addHierarchyListener, addInputMethodListener, addKeyListener, addMouseListener, addMouseMotionListener, addMouseWheelListener, bounds, checkImage, checkImage, coalesceEvents, contains, createImage, createImage, createVolatileImage, createVolatileImage, disableEvents, dispatchEvent, enable, enableEvents, enableInputMethods, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, getBackground, getBounds, getColorModel, getComponentListeners, getComponentOrientation, getCursor, getDropTarget, getFocusCycleRootAncestor, getFocusListeners, getFocusTraversalKeysEnabled, getFont, getForeground, getGraphicsConfiguration, getHierarchyBoundsListeners, getHierarchyListeners, getIgnoreRepaint, getInputContext, getInputMethodListeners, getInputMethodRequests, getKeyListeners, getLocale, getLocation, getLocationOnScreen, getMouseListeners, getMouseMotionListeners, getMousePosition, getMouseWheelListeners, getName, getParent, getPropertyChangeListeners, getPropertyChangeListeners, getSize, getToolkit, getTreeLock, gotFocus, handleEvent, hasFocus, imageUpdate, inside, isBackgroundSet, isCursorSet, isDisplayable, isEnabled, isFocusable, isFocusOwner, isFocusTraversable, isFontSet, isForegroundSet, isLightweight, isMaximumSizeSet, isMinimumSizeSet, isPreferredSizeSet, isShowing, isValid, isVisible, keyDown, keyUp, list, list, list, location, lostFocus, mouseDown, mouseDrag, mouseEnter, mouseExit, mouseMove, mouseUp, move, nextFocus, paintAll, postEvent, prepareImage, prepareImage, processComponentEvent, processFocusEvent, processHierarchyBoundsEvent, processHierarchyEvent, processInputMethodEvent, processMouseWheelEvent, remove, removeComponentListener, removeFocusListener, removeHierarchyBoundsListener, removeHierarchyListener, removeInputMethodListener, removeKeyListener, removeMouseListener, removeMouseMotionListener, removeMouseWheelListener, removePropertyChangeListener, removePropertyChangeListener, repaint, repaint, repaint, requestFocus, requestFocus, requestFocusInWindow, resize, resize, setBounds, setBounds, setComponentOrientation, setCursor, setDropTarget, setFocusable, setFocusTraversalKeysEnabled, setIgnoreRepaint, setLocale, setLocation, setLocation, setMixingCutoutShape, setName, setSize, setSize, show, show, size, toString, transferFocus, transferFocusBackward, transferFocusUpCycle
-
Field Details
-
PALETTE_HEX
Public color palette (hex) for HTML legends and consistency across pages. -
PALETTE
Public color palette as AWT Color objects for chart rendering.
-
-
Constructor Details
-
JLineGraph
public JLineGraph()Create a new JLineGraph with default styling and an empty dataset.
-
-
Method Details
-
settingsChanged
Description copied from interface:SettingsChangeListenerInvoked when application settings have been changed and persisted. Implementations should read the desired values from the Settings helper and update any runtime state accordingly.- Specified by:
settingsChangedin interfaceSettingsChangeListener
-
setJitterEnabled
Enable or disable rendering jitter at runtime.- Parameters:
enabled- true to enable jitter, false to draw raw values
-
isJitterEnabled
Query whether rendering jitter is currently enabled.- Returns:
- true when jitter is enabled, false otherwise
-
setJitterDeterministic
Enable/disable deterministic (seeded) jitter. When enabled, jitter will be generated from a java.util.Random seeded withjitterSeed(or 0 when seed is null).- Parameters:
deterministic- true to use a seeded RNG, false to use non-deterministic RNG
-
isJitterDeterministic
Query whether deterministic jitter is enabled.- Returns:
- true when deterministic (seeded) jitter is enabled
-
setJitterSeed
Set the seed used when deterministic jitter is enabled. Pass null to clear the seed (will use 0 when a deterministic RNG is created).- Parameters:
seed- seed value or null to clear
-
getJitterSeed
Return the currently configured jitter seed or null when unset.- Returns:
- configured seed value or null when not set
-
updateWithData
Replace the current dataset with the provided list of skill value series. Each inner list represents a single session and must contain NUMBER_OF_SKILLS entries.- Parameters:
allSkillValues- list of sessions where each session is a list of integer skill values (older sessions first)
-
updateWithGroupedData
Update the component with grouped plots. Each group is determined by the prefix of the part code (e.g. 'P1' from 'P1_1'). For each group we render a separate small chart stacked vertically.- Parameters:
allSkillValues- list of sessions (older first) where each session is a list of integer skill valuespartCodes- array of part codes aligned with columns in each session row
-
updateWithGroupedDataByDate
public void updateWithGroupedDataByDate(List<LocalDate> dates, List<List<Integer>> rows, String[] partCodes) Plot grouped data over time. Dates are used as the X axis (oldest first). Each skill within a group is drawn as its own line (one series per skill) with point markers and a color-blind friendly palette. Legend placed in the upper-right corner.- Parameters:
dates- chronological list of session dates (oldest first)rows- list of session rows where each row is a list of integer scorespartCodes- array of part codes aligned with the columns in each row
-
updateWithGroupedDataByDate
public void updateWithGroupedDataByDate(List<LocalDate> dates, List<List<Integer>> rows, String[] partCodes, String[] partLabels) Plot grouped data over time with optional human-friendly labels. Each providedpartCodesentry maps to a column index insiderowsand (optionally) a friendly label supplied inpartLabels. The dates list must be ordered oldest-first and must be parallel to the rows list.- Parameters:
dates- chronological list of session dates (oldest first)rows- list of session rows where each row is a list of integer scorespartCodes- array of part codes aligned with the columns in each rowpartLabels- optional human friendly labels parallel topartCodes
-
saveGroupedCharts
public Map<String,Path> saveGroupedCharts(Path dir, String baseName, int width, int heightPerGroup) throws IOException Save each grouped subchart as an individual PNG file. The method writes files named {baseName}-{group}.png into the provided directory and returns a map of group -> written path. Caller must ensure grouped data has been rendered (updateWithGroupedData called) prior to invoking this.- Parameters:
dir- directory to write files intobaseName- base filename (no extension) to prefix each filewidth- image width in pixelsheightPerGroup- per-group image height in pixels- Returns:
- ordered map of group id to written file path
- Throws:
IOException- on I/O error
-
showEmptyGrouped
Show an empty grouped chart using the provided part codes. This will render one row of zeros sized to the number of parts so the UI shows grouped axes and placeholders even when no session data exists yet.- Parameters:
partCodes- array of part codes used to determine the number of columns
-
saveChart
Save the current chart to a PNG file. If the chart is empty this will still export the rendered chart panel contents.- Parameters:
outputPath- path to write the PNG file towidth- image width in pixelsheight- image height in pixels- Throws:
IOException- if writing fails
-