Skip to content

Commit

Permalink
add log scale for scatter plot
Browse files Browse the repository at this point in the history
  • Loading branch information
mustafasaifee42 committed Mar 25, 2024
1 parent 68152a7 commit ec04b93
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 22 deletions.
21 changes: 21 additions & 0 deletions src/Components/AggregatedDataExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ function AggregatedDataExplorer(props: Props) {
signatureSolution: undefined,
signatureSolutionForDataList: 'All',
keepAxisSame: false,
xScaleType: 'linear',
yScaleType: 'linear',
};

const [state, dispatch] = useReducer(Reducer, initialState);
Expand Down Expand Up @@ -202,18 +204,35 @@ function AggregatedDataExplorer(props: Props) {
payload: useSameRange,
});
};

const updateBarLayout = (verticalBarLayout: boolean) => {
dispatch({
type: 'UPDATE_BAR_LAYOUT',
payload: verticalBarLayout,
});
};

const updateKeepAxisSame = (d: boolean) => {
dispatch({
type: 'UPDATE_KEEP_AXIS_SAME',
payload: d,
});
};

const updateXScaleType = (d: 'linear' | 'log') => {
dispatch({
type: 'UPDATE_X_SCALE_TYPE',
payload: d,
});
};

const updateYScaleType = (d: 'linear' | 'log') => {
dispatch({
type: 'UPDATE_Y_SCALE_TYPE',
payload: d,
});
};

return (
<div>
<div
Expand Down Expand Up @@ -287,6 +306,8 @@ function AggregatedDataExplorer(props: Props) {
updateBarLayout,
updateSignatureSolutionForDataList,
updateKeepAxisSame,
updateXScaleType,
updateYScaleType,
}}
>
<div
Expand Down
18 changes: 18 additions & 0 deletions src/Components/CountryVisualization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ function CountryVisualization(props: Props) {
disaggregationGraphType: 'country',
disaggregationOrder: 'first',
keepAxisSame: false,
xScaleType: 'linear',
yScaleType: 'linear',
};

const [state, dispatch] = useReducer(Reducer, initialState);
Expand Down Expand Up @@ -278,6 +280,20 @@ function CountryVisualization(props: Props) {
payload: d,
});
};

const updateXScaleType = (d: 'linear' | 'log') => {
dispatch({
type: 'UPDATE_X_SCALE_TYPE',
payload: d,
});
};

const updateYScaleType = (d: 'linear' | 'log') => {
dispatch({
type: 'UPDATE_Y_SCALE_TYPE',
payload: d,
});
};
return (
<Context.Provider
// eslint-disable-next-line react/jsx-no-constructed-context-values
Expand Down Expand Up @@ -307,6 +323,8 @@ function CountryVisualization(props: Props) {
updateDisaggregationGraphType,
updateDisaggregationOrder,
updateKeepAxisSame,
updateXScaleType,
updateYScaleType,
}}
>
<div className='undp-container'>
Expand Down
4 changes: 4 additions & 0 deletions src/Context/Context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const Context = createContext<CtxDataType>({
signatureSolutionForDataList: 'All',
showReference: false,
keepAxisSame: false,
xScaleType: 'linear',
yScaleType: 'linear',
updateGraphType: (
_d:
| 'scatterPlot'
Expand Down Expand Up @@ -76,6 +78,8 @@ const Context = createContext<CtxDataType>({
| 'Resilience',
) => {},
updateKeepAxisSame: (_d: boolean) => {},
updateXScaleType: (_d: 'linear' | 'log') => {},
updateYScaleType: (_d: 'linear' | 'log') => {},
});

export default Context;
4 changes: 4 additions & 0 deletions src/Context/Reducer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ export default (state: any, action: any) => {
return { ...state, disaggregationOrder: action.payload };
case 'UPDATE_KEEP_AXIS_SAME':
return { ...state, keepAxisSame: action.payload };
case 'UPDATE_X_SCALE_TYPE':
return { ...state, xScaleType: action.payload };
case 'UPDATE_Y_SCALE_TYPE':
return { ...state, yScaleType: action.payload };
default:
return { ...state };
}
Expand Down
71 changes: 49 additions & 22 deletions src/GrapherComponent/ScatterPlot/Graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import maxBy from 'lodash.maxby';
import max from 'lodash.max';
import orderBy from 'lodash.orderby';
import { Delaunay } from 'd3-delaunay';
import { scaleOrdinal, scaleLinear, scaleThreshold, scaleSqrt } from 'd3-scale';
import {
scaleOrdinal,
scaleLinear,
scaleThreshold,
scaleSqrt,
scaleLog,
} from 'd3-scale';
import minBy from 'lodash.minby';
import UNDPColorModule from 'undp-viz-colors';
import flattenDeep from 'lodash.flattendeep';
Expand Down Expand Up @@ -49,6 +55,8 @@ export function Graph(props: Props) {
selectedIncomeGroups,
selectedCountryGroup,
keepAxisSame,
xScaleType,
yScaleType,
} = useContext(Context) as CtxDataType;
const [selectedColor, setSelectedColor] = useState<string | undefined>(
undefined,
Expand Down Expand Up @@ -342,17 +350,28 @@ export function Graph(props: Props) {
: refYVal
: (minBy(dataFormatted, d => d.yVal)?.yVal as number)
: 0;

const xScale = scaleLinear()
.domain([xMinValue > 0 ? 0 : xMinValue, xMaxValue])
.range([0, graphWidth])
.nice();
const yScale = scaleLinear()
.domain([yMinValue > 0 ? 0 : yMinValue, yMaxValue])
.range([graphHeight, 0])
.nice();
const xTicks = xScale.ticks(5);
const yTicks = yScale.ticks(5);
const xScaleLogAllowed = !(
xScaleType === 'linear' ||
fullArray.filter(d => (d.x as number) <= 0).length > 0
);
const yScaleLogAllowed = !(
yScaleType === 'linear' ||
fullArray.filter(d => (d.y as number) <= 0).length > 0
);
const xScale = !xScaleLogAllowed
? scaleLinear()
.domain([xMinValue > 0 ? 0 : xMinValue, xMaxValue])
.range([0, graphWidth])
.nice()
: scaleLog().domain([xMinValue, xMaxValue]).range([0, graphWidth]).nice();
const yScale = !yScaleLogAllowed
? scaleLinear()
.domain([yMinValue > 0 ? 0 : yMinValue, yMaxValue])
.range([graphHeight, 0])
.nice()
: scaleLog().domain([yMinValue, yMaxValue]).range([graphHeight, 0]).nice();
const xTicks = !xScaleLogAllowed ? xScale.ticks(5) : xScale.ticks(3);
const yTicks = !yScaleLogAllowed ? yScale.ticks(5) : yScale.ticks(3);
const voronoiDiagram = Delaunay.from(
dataFormatted,
d => xScale(d.xVal as number),
Expand Down Expand Up @@ -552,6 +571,7 @@ export function Graph(props: Props) {
stroke='#AAA'
strokeWidth={1}
strokeDasharray='4,8'
opacity={yScaleLogAllowed && i === 0 ? 0 : 1}
/>
<text
x={0}
Expand All @@ -569,21 +589,21 @@ export function Graph(props: Props) {
<line
x1={0}
x2={graphWidth}
y1={yScale(0)}
y2={yScale(0)}
y1={yScaleLogAllowed ? graphHeight : yScale(0)}
y2={yScaleLogAllowed ? graphHeight : yScale(0)}
stroke={UNDPColorModule.graphGray}
strokeWidth={1}
/>
<text
x={0}
y={yScale(0)}
y={yScaleLogAllowed ? graphHeight : yScale(0)}
fill={UNDPColorModule.graphGray}
textAnchor='end'
fontSize={12}
dy={4}
dx={-3}
>
0
{yScaleLogAllowed ? '' : 0}
</text>
<text
transform={`translate(-50, ${graphHeight / 2}) rotate(-90)`}
Expand All @@ -602,6 +622,7 @@ export function Graph(props: Props) {
TRUNCATE_MAX_TEXT_LENGTH,
)}...`
: yIndicatorMetaData.IndicatorLabel}
{yScaleLogAllowed ? ' (Log scale)' : ''}
</text>
</g>
<g>
Expand All @@ -615,14 +636,15 @@ export function Graph(props: Props) {
stroke='#AAA'
strokeWidth={1}
strokeDasharray='4,8'
opacity={xScaleLogAllowed && i === 0 ? 0 : 1}
/>
<text
x={xScale(d)}
y={graphHeight}
fill={UNDPColorModule.graphGray}
textAnchor='middle'
fontSize={12}
dy={12}
dy={15}
>
{Math.abs(d) < 1 ? d : format('~s')(d).replace('G', 'B')}
</text>
Expand All @@ -631,20 +653,20 @@ export function Graph(props: Props) {
<line
y1={0}
y2={graphHeight}
x1={xScale(0)}
x2={xScale(0)}
x1={xScaleLogAllowed ? 0 : xScale(0)}
x2={xScaleLogAllowed ? 0 : xScale(0)}
stroke={UNDPColorModule.graphGray}
strokeWidth={1}
/>
<text
x={xScale(0)}
x={xScaleLogAllowed ? 0 : xScale(0)}
y={graphHeight}
fill={UNDPColorModule.graphGray}
textAnchor='middle'
fontSize={12}
dy={15}
>
{0}
{xScaleLogAllowed ? '' : 0}
</text>
<text
transform={`translate(${graphWidth / 2}, ${graphHeight})`}
Expand All @@ -664,6 +686,7 @@ export function Graph(props: Props) {
TRUNCATE_MAX_TEXT_LENGTH,
)}...`
: xIndicatorMetaData.IndicatorLabel}
{xScaleLogAllowed ? ' (Log scale)' : ''}
</text>
</g>

Expand Down Expand Up @@ -866,7 +889,11 @@ export function Graph(props: Props) {
: UNDPColorModule.graphGray
}
/>
{showLabel ? (
{showLabel &&
(selectedCountries.length === 0 ||
selectedCountries.indexOf(
countryData['Country or Area'],
) !== -1) ? (
<text
fontSize={10}
fill={
Expand Down
24 changes: 24 additions & 0 deletions src/GrapherComponent/Settings/ScatterPlotSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export function ScatterPlotSettings(props: Props) {
showMostRecentData,
selectedCountryOrRegion,
showReference,
xScaleType,
yScaleType,
updateColorIndicator,
updateXAxisIndicator,
updateYAxisIndicator,
Expand All @@ -49,6 +51,8 @@ export function ScatterPlotSettings(props: Props) {
updateShowMostRecentData,
updateShowReference,
updateKeepAxisSame,
updateXScaleType,
updateYScaleType,
} = useContext(Context) as CtxDataType;
const scatterPlotIndicators = indicators.filter(d => !d.IsCategorical);
const sizeIndicators = indicators.filter(d => d.Sizing);
Expand Down Expand Up @@ -252,6 +256,26 @@ export function ScatterPlotSettings(props: Props) {
>
Use same axes to compare between years
</Checkbox>
<Checkbox
style={{ margin: 0 }}
className='undp-checkbox'
checked={xScaleType === 'log'}
onChange={e => {
updateXScaleType(e.target.checked ? 'log' : 'linear');
}}
>
Use log scale for x-axis
</Checkbox>
<Checkbox
style={{ margin: 0 }}
className='undp-checkbox'
checked={yScaleType === 'log'}
onChange={e => {
updateYScaleType(e.target.checked ? 'log' : 'linear');
}}
>
Use log scale for y-axis
</Checkbox>
</div>
</div>
{!selectedCountryOrRegion && countries.length > 1 ? (
Expand Down
18 changes: 18 additions & 0 deletions src/RegionVisualization/Visualization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ function VisualizationEl(props: Props) {
disaggregationGraphType: 'global',
disaggregationOrder: 'first',
keepAxisSame: false,
xScaleType: 'linear',
yScaleType: 'linear',
};

const [state, dispatch] = useReducer(Reducer, initialState);
Expand Down Expand Up @@ -277,6 +279,20 @@ function VisualizationEl(props: Props) {
payload: d,
});
};

const updateXScaleType = (d: 'linear' | 'log') => {
dispatch({
type: 'UPDATE_X_SCALE_TYPE',
payload: d,
});
};

const updateYScaleType = (d: 'linear' | 'log') => {
dispatch({
type: 'UPDATE_Y_SCALE_TYPE',
payload: d,
});
};
return (
<Context.Provider
// eslint-disable-next-line react/jsx-no-constructed-context-values
Expand Down Expand Up @@ -306,6 +322,8 @@ function VisualizationEl(props: Props) {
updateDisaggregationGraphType,
updateDisaggregationOrder,
updateKeepAxisSame,
updateXScaleType,
updateYScaleType,
}}
>
<div>
Expand Down
4 changes: 4 additions & 0 deletions src/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ export interface CtxDataType {
| 'Poverty and Inequality'
| 'Resilience';
keepAxisSame: boolean;
xScaleType: 'linear' | 'log';
yScaleType: 'linear' | 'log';
updateGraphType: (
_d:
| 'scatterPlot'
Expand Down Expand Up @@ -211,6 +213,8 @@ export interface CtxDataType {
| 'Resilience',
) => void;
updateKeepAxisSame: (_d: boolean) => void;
updateXScaleType: (_d: 'linear' | 'log') => void;
updateYScaleType: (_d: 'linear' | 'log') => void;
}

export interface CountryListType {
Expand Down

0 comments on commit ec04b93

Please sign in to comment.