Skip to content

Commit

Permalink
Externalities: Add graphics for first scenario
Browse files Browse the repository at this point in the history
  • Loading branch information
nikolas committed Mar 6, 2025
1 parent 6ea62c8 commit 9a5c92d
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 1 deletion.
8 changes: 8 additions & 0 deletions media/js/src/GraphEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import RevenueElasticityEditor from './editors/RevenueElasticityEditor.jsx';
import OptimalChoiceCostMinimizingEditor from './editors/OptimalChoiceCostMinimizingEditor.jsx';
import TaxationLinearDemandEditor from './editors/TaxationLinearDemandEditor.jsx';
import TaxRevenueEditor from './editors/TaxRevenueEditor.jsx';
import NegativeProductionExternalityProducerEditor from './editors/NegativeProductionExternalityProducerEditor.jsx';

import JXGBoard from './JXGBoard.jsx';
import GraphPane from './GraphPane.jsx';
Expand Down Expand Up @@ -330,6 +331,13 @@ export default class GraphEditor extends React.Component {
{...commonEditorProps}
{...this.props}
/>;
} else if (this.props.gType === 26) {
rightSide =
<NegativeProductionExternalityProducerEditor
updateGraph={this.props.updateGraph}
{...commonEditorProps}
{...this.props}
/>;
}

const hasIntersection = ![
Expand Down
9 changes: 9 additions & 0 deletions media/js/src/GraphViewer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import OptimalChoiceConsumptionEditor from './editors/OptimalChoiceConsumption.j
import CostFunctionsEditor from './editors/CostFunctionsEditor.jsx';
import OptimalChoiceCostMinimizingEditor from './editors/OptimalChoiceCostMinimizingEditor.jsx';
import TaxationLinearDemandEditor from './editors/TaxationLinearDemandEditor.jsx';
import NegativeProductionExternalityProducerEditor from
'./editors/NegativeProductionExternalityProducerEditor.jsx';

import ExportGraphButton from './buttons/ExportGraphButton.jsx';
import ResetGraphButton from './buttons/ResetGraphButton.jsx';
Expand Down Expand Up @@ -330,6 +332,13 @@ export default class GraphViewer extends React.Component {
{...commonViewerProps}
{...this.props}
/>;
} else if (this.props.gType === 26) {
rightSide =
<NegativeProductionExternalityProducerEditor
updateGraph={this.props.updateGraph}
{...commonViewerProps}
{...this.props}
/>;
}

return (
Expand Down
12 changes: 12 additions & 0 deletions media/js/src/JXGBoard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,18 @@ export default class JXGBoard extends React.Component {
xTicks = this.visibleTicks;
yTicks = xTicks;
break;
case 26:
xTicks = this.visibleTicks;
yTicks = xTicks;
break;
case 28:
xTicks = this.visibleTicks;
yTicks = xTicks;
break;
case 27:
xTicks = this.visibleTicks;
yTicks = xTicks;
break;
default:
xAxisLabel = options.gXAxisLabel ? options.gXAxisLabel : 'x';
yAxisLabel = options.gYAxisLabel ? options.gYAxisLabel : 'y';
Expand Down
137 changes: 137 additions & 0 deletions media/js/src/editors/NegativeProductionExternalityProducerEditor.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import React from 'react';
import PropTypes from 'prop-types';
import RangeEditor from '../form-components/RangeEditor.jsx';
import { handleFormUpdate } from '../utils.js';

export default class NegativeProductionExternalityProducerEditor extends React.Component {
render() {
const me = this;

const modesLeft = [
'Negative Producer Externality',
'Unregulated',
'Welfare',
];
const modesRight = [
'Pigouvian Tax',
'Pigouvian Tax (Welfare)',
];

const radioButtons1 = modesLeft.map((optionTitle, idx) =>
<div key={idx} className="form-check">
<input
type="radio" id={`functionChoice-${idx}`}
className="form-check-input"
value={idx}
name="gFunctionChoice"
checked={me.props.gFunctionChoice === idx}
onChange={handleFormUpdate.bind(me)} />
<label
className="form-check-label"
htmlFor={`functionChoice-${idx}`}>
{optionTitle}
</label>
</div>
);

const radioButtons2 = modesRight.map(function(optionTitle, idx) {
const newIdx = idx + modesLeft.length;
return (
<div key={newIdx} className="form-check">
<input
type="radio" id={`functionChoice-${newIdx}`}
className="form-check-input"
value={newIdx}
name="gFunctionChoice"
checked={me.props.gFunctionChoice === newIdx}
onChange={handleFormUpdate.bind(me)} />
<label
className="form-check-label"
htmlFor={`functionChoice-${newIdx}`}>
{optionTitle}
</label>
</div>
);
});

return (
<>
<div className="row">
<div className="col">
{radioButtons1}
</div>
<div className="col">
{radioButtons2}
</div>
</div>

<div>
{this.props.displaySliders && (
<>
<RangeEditor
label="MB Constant"
rawLabel={true}
id="gA1"
value={this.props.gA1}
min={0}
max={10000}
handler={handleFormUpdate.bind(this)} />

<RangeEditor
label="MC Constant"
rawLabel={true}
id="gA2"
value={this.props.gA2}
min={0}
max={10000}
handler={handleFormUpdate.bind(this)} />

<RangeEditor
label="MC Slope"
rawLabel={true}
id="gA3"
value={this.props.gA3}
min={0.01}
max={35}
handler={handleFormUpdate.bind(this)} />

<RangeEditor
label="EMC Constant"
rawLabel={true}
id="gA4"
value={this.props.gA4}
min={0}
max={10000}
handler={handleFormUpdate.bind(this)} />

<RangeEditor
label="EMC Slope"
rawLabel={true}
id="gA5"
value={this.props.gA5}
min={0.0}
max={35}
handler={handleFormUpdate.bind(this)} />
</>
)}
</div>
</>
);
}
}

NegativeProductionExternalityProducerEditor.propTypes = {
gType: PropTypes.number.isRequired,

gA1: PropTypes.number.isRequired,
gA2: PropTypes.number.isRequired,
gA3: PropTypes.number.isRequired,
gA4: PropTypes.number.isRequired,
gA5: PropTypes.number.isRequired,
gA6: PropTypes.number,

gFunctionChoice: PropTypes.number.isRequired,
gToggle: PropTypes.bool.isRequired,

displaySliders: PropTypes.bool.isRequired
};
5 changes: 5 additions & 0 deletions media/js/src/graphUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import {
import {
defaults as cobbDouglasDefaults
} from './graphs/CobbDouglasGraph.js';
import {
defaults as externalitiesDefaults
} from './graphs/NegativeProductionExternalityProducerGraph.js';

/**
* Set defaults to the given state update object based on toggle and
Expand Down Expand Up @@ -130,6 +133,8 @@ export const getDefaultGraphState = function(graphType, state) {
});
} else if (graphType === 25) {
Object.assign(state, linearDemandSupplySurplusDefaults[0]);
} else if (graphType >= 26 && graphType <= 28) {
Object.assign(state, externalitiesDefaults[0]);
}

return state;
Expand Down
142 changes: 141 additions & 1 deletion media/js/src/graphs/NegativeProductionExternalityProducerGraph.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,146 @@
import {Graph} from './Graph.js';
import {Graph, positiveRange} from './Graph.js';

export const defaults = [
{
gXAxisMax: 1000,
gYAxisMax: 2500,
gA1: 1500,
gA2: 500,
gA3: 2,
gA4: 50,
gA5: 2
}
];

// Marginal Benefit
const mb = function(a) {
return a;
};

const mc = function(c, d, q) {
return c + d * q;
};

// External Marginal Cost
const emc = function(f, g, q) {
return f + g * q;
};

/*const pemc = function(f, g, p) {
return (p - f) / g;
};*/


// Social Marginal Cost
const smc = function(c, d, f, g, q) {
return mc(c, d, q) + emc(f, g, q);
};

/*const psmc = function(c, d, f, g, p) {
return (p - c - f) / (d + g);
};*/

export class NegativeProductionExternalityProducerGraph extends Graph {
static getGraphPane(gFunctionChoice) {
return [
{
label: 'Unregulated Output q*',
color: 'red',
value: 500
},
{
label: 'Socially Desirable Output q<sup>soc</sup>',
color: 'orange',
value: 247.5
},
{
label: 'Market Price P*',
color: 'red',
value: 1500
},
];
}
make() {
const me = this;

const mbLine = function() {
return mb(me.options.gA1);
};

this.l2 = this.board.create(
'functiongraph',
[positiveRange(mbLine), 0, this.options.gXAxisMax], {
name: 'MB',
withLabel: true,
label: {
strokeColor: this.l2Color
},
strokeWidth: 2,
strokeColor: this.l2Color,
fixed: true,
highlight: false
}
);

const mcLine = function(x) {
return mc(me.options.gA2, me.options.gA3, x);
};

this.l1 = this.board.create(
'functiongraph',
[positiveRange(mcLine), 0, this.options.gXAxisMax], {
name: 'MC',
withLabel: true,
label: {
strokeColor: this.l1Color
},
strokeWidth: 2,
strokeColor: this.l1Color,
fixed: true,
highlight: false
}
);

const emcLine = function(x) {
return emc(me.options.gA4, me.options.gA5, x);
};

this.l3 = this.board.create(
'functiongraph',
[positiveRange(emcLine), 0, this.options.gXAxisMax], {
name: 'EMC',
withLabel: true,
label: {
strokeColor: this.l3Color
},
strokeWidth: 2,
strokeColor: this.l3Color,
fixed: true,
highlight: false
}
);

const smcLine = function(x) {
return smc(
me.options.gA2, me.options.gA3,
me.options.gA4, me.options.gA5, x);
};

this.l4 = this.board.create(
'functiongraph',
[positiveRange(smcLine), 0, this.options.gXAxisMax], {
name: 'SMC',
withLabel: true,
label: {
strokeColor: this.l4Color
},
strokeWidth: 2,
strokeColor: this.l4Color,
fixed: true,
highlight: false
}
);
}
}

export const mkNegativeProductionExternalityProducer = function(board, options) {
Expand Down

0 comments on commit 9a5c92d

Please sign in to comment.