Skip to content
Snippets Groups Projects
Commit d9a8e67d authored by Cee Nell's avatar Cee Nell
Browse files

get checkbox text workinggit add .

parent 09edcc29
No related branches found
No related tags found
1 merge request!22Make beeswarm vertical
...@@ -4,44 +4,44 @@ ...@@ -4,44 +4,44 @@
<p> <p>
Everyone needs access to clean water. Water insecurity is influenced by a number of social vulnerability indicators. This includes Everyone needs access to clean water. Water insecurity is influenced by a number of social vulnerability indicators. This includes
<span <span
:class="['highlight', 'demographicCharacteristics', { checked: isChecked.demographicCharacteristics }]" :class="['highlight', 'Demographiccharacteristics', { checked: isChecked.Demographiccharacteristics }]"
@click="toggleCategory('demographicCharacteristics')" @click="toggleCategory('Demographiccharacteristics')"
> >
demographic characteristics demographic characteristics
</span>, </span>,
<span <span
:class="['highlight', 'health', { checked: isChecked.health }]" :class="['highlight', 'Health', { checked: isChecked.Health }]"
@click="toggleCategory('health')" @click="toggleCategory('Health')"
> >
health health
</span>, </span>,
<span <span
:class="['highlight', 'livingConditions', { checked: isChecked.livingConditions }]" :class="['highlight', 'Livingconditions', { checked: isChecked.Livingconditions }]"
@click="toggleCategory('livingConditions')" @click="toggleCategory('Livingconditions')"
> >
living conditions living conditions
</span>, </span>,
<span <span
:class="['highlight', 'socioeconomicStatus', { checked: isChecked.socioeconomicStatus }]" :class="['highlight', 'Socioeconomicstatus', { checked: isChecked.Socioeconomicstatus }]"
@click="toggleCategory('socioeconomicStatus')" @click="toggleCategory('Socioeconomicstatus')"
> >
socioeconomic status socioeconomic status
</span>, </span>,
<span <span
:class="['highlight', 'riskPerception', { checked: isChecked.riskPerception }]" :class="['highlight', 'Riskperception', { checked: isChecked.Riskperception }]"
@click="toggleCategory('riskPerception')" @click="toggleCategory('Riskperception')"
> >
risk perception risk perception
</span>, </span>,
<span <span
:class="['highlight', 'landTenure', { checked: isChecked.landTenure }]" :class="['highlight', 'Landtenure', { checked: isChecked.Landtenure }]"
@click="toggleCategory('landTenure')" @click="toggleCategory('Landtenure')"
> >
land tenure land tenure
</span>, and </span>, and
<span <span
:class="['highlight', 'exposureToStressors', { checked: isChecked.exposureToStressors }]" :class="['highlight', 'Exposure', { checked: isChecked.Exposure }]"
@click="toggleCategory('exposureToStressors')" @click="toggleCategory('Exposure')"
> >
exposure to stressors exposure to stressors
</span> (like drought or pollution). </span> (like drought or pollution).
...@@ -50,297 +50,303 @@ ...@@ -50,297 +50,303 @@
<div id="beeswarm-chart-container"></div> <div id="beeswarm-chart-container"></div>
</section> </section>
</template> </template>
<script setup> <script setup>
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import * as d3 from 'd3'; import * as d3 from 'd3';
// Global variables // Global variables
const publicPath = import.meta.env.BASE_URL; const publicPath = import.meta.env.BASE_URL;
const dataSet1 = ref([]); const dataSet1 = ref([]);
const dataSet2 = ref([]); const dataSet2 = ref([]);
const selectedDataSet = ref('dataSet1'); const selectedDataSet = ref('dataSet1');
const data = ref([]); const data = ref([]);
let simulation; let simulation;
// Set up SVG // Set up SVG
let svg; let svg;
const height = 800; const height = 800;
const width = 800; const width = 800;
const margin = { top: 30, right: 20, bottom: 20, left: 30 }; const margin = { top: 30, right: 20, bottom: 20, left: 30 };
const isChecked = ref({ const isChecked = ref({
demographicCharacteristics: true, Demographiccharacteristics: true,
health: true, Health: true,
livingConditions: true, Livingconditions: true,
socioeconomicStatus: true, Socioeconomicstatus: true,
riskPerception: true, Riskperception: true,
landTenure: true, Landtenure: true,
exposureToStressors: true Exposure: true
}); });
// Set colors for bubble charts // Set colors for bubble charts
const dimensionColors = { const dimensionColors = {
Demographiccharacteristics: "#092836", Demographiccharacteristics: "#092836",
Landtenure: "#1b695e", Landtenure: "#1b695e",
Livingconditions: "#7a5195", Livingconditions: "#7a5195",
Socioeconomicstatus: "#2a468f", Socioeconomicstatus: "#2a468f",
Health: "#ef5675", Health: "#ef5675",
Riskperception: "#ff764a", Riskperception: "#ff764a",
Exposure: "#ffa600" Exposure: "#ffa600"
}; };
// Load data and then make chart // Load data and then make chart
onMounted(async () => { onMounted(async () => {
try { try {
await loadDatasets(); await loadDatasets();
data.value = selectedDataSet.value === 'dataSet1' ? dataSet1.value : dataSet2.value; data.value = selectedDataSet.value === 'dataSet1' ? dataSet1.value : dataSet2.value;
if (data.value.length > 0) { if (data.value.length > 0) {
createBeeswarmChart(); createBeeswarmChart();
} else { } else {
console.error('Error loading data'); console.error('Error loading data');
}
} catch (error) {
console.error('Error during component mounting', error);
}
});
async function loadDatasets() {
try {
dataSet1.value = await loadData('determinant_uncertainty.csv');
dataSet2.value = await loadData('indicator_uncertainty.csv');
} catch (error) {
console.error('Error loading datasets', error);
}
}
async function loadData(fileName) {
try {
const data = await d3.csv(publicPath + fileName, d => {
d.level_agreement = +(+d.level_agreement).toFixed(2);
d.evidence_val = +d.evidence_val;
d.sig_value = +d.sig_value;
return d;
});
return data;
} catch (error) {
console.error(`Error loading data from ${fileName}`, error);
return [];
} }
} catch (error) {
console.error('Error during component mounting', error);
} }
});
function createBeeswarmChart() {
svg = d3 async function loadDatasets() {
.select('#beeswarm-chart-container') try {
.append('svg') dataSet1.value = await loadData('determinant_uncertainty.csv');
.attr('class', 'beeswarmSvg') dataSet2.value = await loadData('indicator_uncertainty.csv');
.attr('width', width) console.log('data in')
.attr('height', height); } catch (error) {
console.error('Error loading datasets', error);
const yScale = d3.scaleLinear()
.domain([40, d3.max(data.value, d => d.level_agreement)])
.range([margin.bottom + height, margin.top]);
// Set radius based on evidence value
const radiusScale = d3.scaleLinear()
.domain([d3.min(data.value, d => d.evidence_val), d3.max(data.value, d => d.evidence_val)])
.range([10, 90]);
const yAxis = svg.append('g')
.attr("transform", "translate(50, 0)")
.call(d3.axisLeft(yScale));
// Add label to y axis
svg.append('text')
.attr("class", "yLabel")
.attr("text-anchor", "start")
.attr("x", 10)
.attr("y", 20)
.text("High level of Agreement");
svg.append('text')
.attr("class", "yLabel")
.attr("text-anchor", "start")
.attr("x", 10)
.attr("y", height - 50)
.text("Inconclusive");
// Set forces
const forceY = d3.forceY(d => yScale(d.level_agreement)).strength(1);
const forceX = d3.forceX(width / 1.5).strength(0.1);
const forceCollide = d3.forceCollide(d => radiusScale(d.evidence_val) + 2);
const forceManyBody = d3.forceManyBody().strength(-15);
const bubbles = svg
.selectAll('.bubble')
.data(data.value)
.enter()
.append('circle')
.attr('class', 'bubble')
.attr('r', d => radiusScale(d.evidence_val))
.style('fill', d => dimensionColors[d.dimension.replace(' ', '')]);
// Run simulation
simulation = d3.forceSimulation()
.force('x', forceX)
.force('y', forceY)
.force('collide', forceCollide)
.force('charge', forceManyBody)
.nodes(data.value)
.on('tick', ticked)
.alpha(0.2);
function ticked() {
bubbles
.attr("cx", d => d.x)
.attr("cy", d => d.y);
}
} }
}
function toggleCategory(category) {
isChecked.value[category] = !isChecked.value[category]; async function loadData(fileName) {
updateChart(); try {
const data = await d3.csv(publicPath + fileName, d => {
d.level_agreement = +(+d.level_agreement).toFixed(2);
d.evidence_val = +d.evidence_val;
d.sig_value = +d.sig_value;
return d;
});
return data;
} catch (error) {
console.error(`Error loading data from ${fileName}`, error);
return [];
} }
}
function createBeeswarmChart() {
svg = d3
.select('#beeswarm-chart-container')
.append('svg')
.attr('class', 'beeswarmSvg')
.attr('width', width)
.attr('height', height);
const yScale = d3.scaleLinear()
.domain([40, d3.max(data.value, d => d.level_agreement)])
.range([margin.bottom + height, margin.top]);
function updateChart() { // Set radius based on evidence value
const yScale = d3.scaleLinear() const radiusScale = d3.scaleLinear()
.domain([30, d3.max(data.value, d => d.level_agreement)]) .domain([d3.min(data.value, d => d.evidence_val), d3.max(data.value, d => d.evidence_val)])
.range([margin.bottom + height, margin.top]); .range([10, 90]);
// Set radius based on evidence value const yAxis = svg.append('g')
const radiusScale = d3.scaleLinear() .attr("transform", "translate(50, 0)")
.domain([d3.min(data.value, d => d.evidence_val), d3.max(data.value, d => d.evidence_val)]) .call(d3.axisLeft(yScale));
.range([10, 90]);
// Add label to y axis
// Filter data based on active categories svg.append('text')
const activeCategories = Object.keys(isChecked.value).filter(category => isChecked.value[category]); .attr("class", "yLabel")
const dataPoints = data.value.filter(d => activeCategories.includes(d.dimension.replace(' ', ''))); .attr("text-anchor", "start")
.attr("x", 10)
// Update existing bubbles and add new bubbles .attr("y", 20)
const bubbles = svg.selectAll(".bubble") .text("High level of Agreement");
.data(dataPoints, d => d.id);
svg.append('text')
// Remove old bubbles .attr("class", "yLabel")
bubbles.exit().remove(); .attr("text-anchor", "start")
.attr("x", 10)
// Update existing bubbles .attr("y", height - 50)
.text("Inconclusive");
// Set forces
const forceY = d3.forceY(d => yScale(d.level_agreement)).strength(1);
const forceX = d3.forceX(width / 1.5).strength(0.1);
const forceCollide = d3.forceCollide(d => radiusScale(d.evidence_val) + 2);
const forceManyBody = d3.forceManyBody().strength(-15);
const bubbles = svg
.selectAll('.bubble')
.data(data.value)
.enter()
.append('circle')
.attr('class', 'bubble')
.attr('r', d => radiusScale(d.evidence_val))
.style('fill', d => dimensionColors[d.dimension.replace(' ', '')]);
// Run simulation
simulation = d3.forceSimulation()
.force('x', forceX)
.force('y', forceY)
.force('collide', forceCollide)
.force('charge', forceManyBody)
.nodes(data.value)
.on('tick', ticked)
.alpha(0.2);
function ticked() {
bubbles bubbles
.attr('r', d => radiusScale(d.evidence_val)) .attr("cx", d => d.x)
.attr('cx', d => d.x) .attr("cy", d => d.y);
.attr('cy', d => d.y)
.style('fill', d => dimensionColors[d.dimension.replace(' ', '')]);
// Add new bubbles
bubbles.enter()
.append('circle')
.attr('class', 'bubble')
.attr('r', d => radiusScale(d.evidence_val))
.attr('cx', () => Math.random() * (width - margin.left - margin.right) + margin.left)
.attr('cy', d => yScale(d.level_agreement))
.style('fill', d => dimensionColors[d.dimension.replace(' ', '')]);
// Restart simulation with new data
simulation.nodes(dataPoints).alpha(0.2).restart();
} }
</script> }
function toggleCategory(category) {
<style scoped lang="scss"> console.log(`Toggle category called for: ${category}`);
$switchWidth: 12rem; isChecked.value[category] = !isChecked.value[category];
$Demographiccharacteristics: #092836; console.log(`Category toggled: ${category}, new value: ${isChecked.value[category]}`);
$Landtenure: #1b695e; updateChart();
$Livingconditions: #7a5195; }
$Socioeconomicstatus: #2a468f;
$Health: #ef5675; function updateChart() {
$Riskperception: #ff764a; console.log('Update chart called');
$Exposure: #ffa600; const yScale = d3.scaleLinear()
.domain([30, d3.max(data.value, d => d.level_agreement)])
#beeswarm-chart-container { .range([margin.bottom + height, margin.top]);
text-align: center;
position: relative; // Set radius based on evidence value
} const radiusScale = d3.scaleLinear()
.domain([d3.min(data.value, d => d.evidence_val), d3.max(data.value, d => d.evidence_val)])
#beeswarm-chart-container svg { .range([10, 90]);
max-width: 100%;
max-height: 100%; // Filter data based on active categories
height: auto; /* Maintain aspect ratio */ const activeCategories = Object.keys(isChecked.value).filter(category => isChecked.value[category]);
display: inline-block; const dataPoints = data.value.filter(d => activeCategories.includes(d.dimension.replace(' ', '')));
} console.log('Active categories:', activeCategories);
console.log('Filtered data points:', dataPoints);
.bubble {
stroke: black; // Update existing bubbles and add new bubbles
stroke-width: 2px; const bubbles = svg.selectAll(".bubble")
fill-opacity: 0.8; .data(dataPoints, d => d.id);
}
// Remove old bubbles
.chart-text { bubbles.exit().remove();
user-select: none;
} // Update existing bubbles
.yLabel { bubbles
font-weight: bold; .attr('r', d => radiusScale(d.evidence_val))
} .attr('cx', d => d.x)
.attr('cy', d => d.y)
.highlight { .style('fill', d => dimensionColors[d.dimension.replace(' ', '')]);
color: white;
padding: 0.25px 5px; // Add new bubbles
border-radius: 10px; bubbles.enter()
white-space: nowrap; .append('circle')
font-weight: bold; .attr('class', 'bubble')
cursor: pointer; /* Add cursor pointer for better UX */ .attr('r', d => radiusScale(d.evidence_val))
transition: all 0.1s; /* Smooth transition for background color and border */ .attr('cx', () => Math.random() * (width - margin.left - margin.right) + margin.left)
} .attr('cy', d => yScale(d.level_agreement))
.style('fill', d => dimensionColors[d.dimension.replace(' ', '')]);
.highlight:not(.checked) {
background-color: white; // Restart simulation with new data
border: 2px solid; simulation.nodes(dataPoints).alpha(0.2).restart();
} }
.highlight.demographicCharacteristics { </script>
background-color: $Demographiccharacteristics;
} <style scoped lang="scss">
.highlight.demographicCharacteristics:not(.checked) { $switchWidth: 12rem;
color: $Demographiccharacteristics; $Demographiccharacteristics: #092836;
border-color: $Demographiccharacteristics; $Landtenure: #1b695e;
} $Livingconditions: #7a5195;
.highlight.landTenure { $Socioeconomicstatus: #2a468f;
background-color: $Landtenure; $Health: #ef5675;
} $Riskperception: #ff764a;
.highlight.landTenure:not(.checked) { $Exposure: #ffa600;
color: $Landtenure;
border-color: $Landtenure; #beeswarm-chart-container {
} text-align: center;
.highlight.livingConditions { position: relative;
background-color: $Livingconditions; }
}
.highlight.livingConditions:not(.checked) { #beeswarm-chart-container svg {
color: $Livingconditions; max-width: 100%;
border-color: $Livingconditions; max-height: 100%;
} height: auto; /* Maintain aspect ratio */
.highlight.socioeconomicStatus { display: inline-block;
background-color: $Socioeconomicstatus; }
}
.highlight.socioeconomicStatus:not(.checked) { .bubble {
color: $Socioeconomicstatus; stroke: black;
border-color: $Socioeconomicstatus; stroke-width: 2px;
} fill-opacity: 0.8;
.highlight.health { }
background-color: $Health;
} .chart-text {
.highlight.health:not(.checked) { user-select: none;
color: $Health; }
border-color: $Health; .yLabel {
} font-weight: bold;
.highlight.riskPerception { }
background-color: $Riskperception;
} .highlight {
.highlight.riskPerception:not(.checked) { color: white;
color: $Riskperception; padding: 0.25px 5px;
border-color: $Riskperception; border-radius: 10px;
} white-space: nowrap;
.highlight.exposureToStressors { font-weight: bold;
background-color: $Exposure; cursor: pointer; /* Add cursor pointer for better UX */
} transition: all 0.1s; /* Smooth transition for background color and border */
.highlight.exposureToStressors:not(.checked) { }
color: $Exposure;
border-color: $Exposure; .highlight:not(.checked) {
} background-color: white;
</style> border: 2px solid;
}
.highlight.Demographiccharacteristics {
background-color: $Demographiccharacteristics;
}
.highlight.Demographiccharacteristics:not(.checked) {
color: $Demographiccharacteristics;
border-color: $Demographiccharacteristics;
}
.highlight.Landtenure {
background-color: $Landtenure;
}
.highlight.Landtenure:not(.checked) {
color: $Landtenure;
border-color: $Landtenure;
}
.highlight.Livingconditions {
background-color: $Livingconditions;
}
.highlight.Livingconditions:not(.checked) {
color: $Livingconditions;
border-color: $Livingconditions;
}
.highlight.Socioeconomicstatus {
background-color: $Socioeconomicstatus;
}
.highlight.Socioeconomicstatus:not(.checked) {
color: $Socioeconomicstatus;
border-color: $Socioeconomicstatus;
}
.highlight.Health {
background-color: $Health;
}
.highlight.Health:not(.checked) {
color: $Health;
border-color: $Health;
}
.highlight.Riskperception {
background-color: $Riskperception;
}
.highlight.Riskperception:not(.checked) {
color: $Riskperception;
border-color: $Riskperception;
}
.highlight.Exposure {
background-color: $Exposure;
}
.highlight.Exposure:not(.checked) {
color: $Exposure;
border-color: $Exposure;
}
</style>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment