Skip to content

Commit

Permalink
Merge pull request #35 from shotnothing/price-bar
Browse files Browse the repository at this point in the history
Price bar
  • Loading branch information
Jocelyn2910 authored Apr 6, 2024
2 parents d1dc775 + 446f6e1 commit 577d6d1
Show file tree
Hide file tree
Showing 14 changed files with 4,235 additions and 210 deletions.
Binary file added .DS_Store
Binary file not shown.
3,597 changes: 3,392 additions & 205 deletions webapp/package-lock.json

Large diffs are not rendered by default.

16 changes: 14 additions & 2 deletions webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,23 @@
"lint": "next lint"
},
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@mui/material": "^5.15.14",
"@sgratzl/chartjs-chart-boxplot": "^4.3.0",
"@types/faker": "^6.6.9",
"bootstrap": "^5.3.3",
"next": "14.1.3",
"next-auth": "^4.24.7",
"chart.js": "^4.4.2",
"d3": "^7.9.0",
"faker": "^5.5.3",
"next": "^14.1.3",
"plotly.js": "^2.30.1",
"react": "^18",
"react-apexcharts": "^1.4.1",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18",
"react-plotly.js": "^2.6.0",
"next-auth": "^4.24.7",
"react-helmet": "^6.1.0",
"react-icons": "^5.0.1"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.legend {
display: flex;
flex-direction: column;
}

.legend-item {
display: flex;
align-items: center;
margin-bottom: 5px;
}

.circle {
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 5px;
}

.label {
font-size: 14px;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import './boxplot-legend.css';


interface LegendItem {
label: string;
color: string;
}

interface BoxPlotLegendProps {
legendItems: LegendItem[];
}

const BoxPlotLegend: React.FC<BoxPlotLegendProps> = ({ legendItems }) => {
return (
<div className="legend">
{legendItems.map((item, index) => (
<div key={index} className="legend-item">
<span className="circle" style={{ backgroundColor: item.color }}></span>
<span className="label">{item.label}</span>
</div>
))}
</div>
);
};

export default BoxPlotLegend;
141 changes: 141 additions & 0 deletions webapp/src/app/(authenticated)/pricebar/components/boxplot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"use client"

import React, { useEffect, useRef } from 'react';
import * as d3 from 'd3';

interface BoxPlotProps {
data: { [key: string]: number };
width: number;
height: number;
svgRef: React.MutableRefObject<SVGSVGElement | null>;
}

const BoxPlot: React.FC<BoxPlotProps> = ({ data, width, height, svgRef }) => {
useEffect(() => {
if (!svgRef.current) return;

const dataArray = Object.values(data);
if (dataArray.length === 0) return;

const margin = { top: 20, right: 50, bottom: 50, left: 2 };
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;

const svg = d3.select(svgRef.current)
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);

const yScale = d3.scaleBand()
.domain(['Box Plot'])
.range([margin.top, innerHeight])
.padding(0.1);

const xScale = d3.scaleLinear()
.domain([d3.min(dataArray)!, d3.max(dataArray)!])
.nice()
.range([margin.left, innerWidth]);

const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);

// Draw box plot
const boxPlotGroup = g.append('g');

const boxHeight = yScale.bandwidth();

Object.entries(data).forEach(([key, value]) => {
// For each key-value pair in the data object
boxPlotGroup.append('rect')
.attr('y', yScale('Box Plot') - 20)
.attr('x', xScale(d3.quantile(dataArray, 0.25)))
.attr('height', 40)
.attr('width', xScale(d3.quantile(dataArray, 0.75)) - xScale(d3.quantile(dataArray, 0.25)))
.attr('fill', 'rgba(0, 0, 0, 0.01)');
});


boxPlotGroup.append('line')
.attr('y1', yScale('Box Plot') - 20)
.attr('y2', yScale('Box Plot') + 20)
.attr('x1', xScale(d3.quantile(dataArray, 0.5)))
.attr('x2', xScale(d3.quantile(dataArray, 0.5)))
.attr('stroke', 'black');

boxPlotGroup.append('line')
.attr('y1', yScale('Box Plot') - 20)
.attr('y2', yScale('Box Plot') + 20)
.attr('x1', xScale(d3.min(dataArray)!))
.attr('x2', xScale(d3.min(dataArray)!))
.attr('stroke', 'black')
.attr('stroke-width', 0.5)
.attr('stroke-dasharray', '3');

boxPlotGroup.append('line')
.attr('y1', yScale('Box Plot') - 20)
.attr('y2', yScale('Box Plot') + 20)
.attr('x1', xScale(d3.max(dataArray)!))
.attr('x2', xScale(d3.max(dataArray)!))
.attr('stroke', 'black')
.attr('stroke-width', 0.5)
.attr('stroke-dasharray', '3');

boxPlotGroup.append('line')
.attr('y1', yScale('Box Plot') - 20)
.attr('y2', yScale('Box Plot') + 20)
.attr('x1', xScale(d3.quantile(dataArray, 0.25)))
.attr('x2', xScale(d3.quantile(dataArray, 0.25)))
.attr('stroke', 'black')


boxPlotGroup.append('line')
.attr('y1', yScale('Box Plot') - 20)
.attr('y2', yScale('Box Plot') + 20)
.attr('x1', xScale(d3.quantile(dataArray, 0.75)))
.attr('x2', xScale(d3.quantile(dataArray, 0.75)))
.attr('stroke', 'black')

boxPlotGroup.append('line')
.attr('y1', yScale('Box Plot'))
.attr('y2', yScale('Box Plot'))
.attr('x1', xScale(d3.min(dataArray)!))
.attr('x2', xScale(d3.quantile(dataArray, 0.25)))
.attr('stroke', 'black')

boxPlotGroup.append('line')
.attr('y1', yScale('Box Plot'))
.attr('y2', yScale('Box Plot'))
.attr('x1', xScale(d3.quantile(dataArray, 0.75)))
.attr('x2', xScale(d3.max(dataArray)!))
.attr('stroke', 'black')

boxPlotGroup.append('line')
.attr('y1', yScale('Box Plot')-20)
.attr('y2', yScale('Box Plot')-20)
.attr('x1', xScale(d3.quantile(dataArray, 0.25)))
.attr('x2', xScale(d3.quantile(dataArray, 0.75)))
.attr('stroke', 'black')

boxPlotGroup.append('line')
.attr('y1', yScale('Box Plot')+20)
.attr('y2', yScale('Box Plot')+20)
.attr('x1', xScale(d3.quantile(dataArray, 0.25)))
.attr('x2', xScale(d3.quantile(dataArray, 0.75)))
.attr('stroke', 'black')

const xAxis = d3.axisBottom(xScale);

g.append('g')
.attr('class', 'x-axis')
.call(xAxis)
.attr("transform", `translate(0, ${innerHeight})`);

}, [data, width, height, svgRef]);

return (
<svg ref={svgRef}></svg>
);
}

export default BoxPlot;
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"use client"

import React, { useEffect, useRef } from 'react';
import * as d3 from 'd3';


interface CurrentPricesProps {
data: { [key: string]: number };
width: number;
height: number;
svgRef: React.MutableRefObject<SVGSVGElement | null>;
}

const CurrentPricesMFLG:React.FC<CurrentPricesProps> = ({ data, width, height, svgRef }) => {

useEffect(() => {
const dataArray = Object.values(data); // Extract values from the object


if (dataArray.length === 0) return;
const margin = { top: 20, right: 50, bottom: 50, left: 2 };
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;

const svg = d3.select(svgRef.current)
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);

const yScale = d3.scaleBand()
.domain(['Box Plot'])
.range([margin.top, innerHeight])
.padding(0.1);

const xScale = d3.scaleLinear()
.domain([d3.min(dataArray)!, d3.max(dataArray)!])
.nice()
.range([margin.left, innerWidth]);

const g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);

// Draw box plot
const boxPlotGroup = g.append('g');

const boxHeight = yScale.bandwidth();


Object.entries(data).forEach(([key, value]) => {
if (key === 'mflg')
boxPlotGroup.append('circle')
.attr('cy', yScale('Box Plot'))
.attr('cx', xScale(value))
.attr('r', 6)
.attr('fill', 'green');
});


}, [data, width, height, svgRef]);

return null;
}

export default CurrentPricesMFLG;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.tooltip {
position: absolute;
background-color: white;
border: 1px solid #ccc;
padding: 5px;
border-radius: 5px;
pointer-events: none;
}
Loading

0 comments on commit 577d6d1

Please sign in to comment.