WFO logo

Snapshots of the taxonomy

WFO Logo

As classified in WFO snapshot

June 2025

latest classification for this taxon

genus

Nuphar Sm.

This genus name was first published in Fl. Graec. Prodr. 1: 361 (1809)  

At the time of this classification snapshot, this genus name was accepted by WFO (placed as the accepted name of a taxon). Its description and other taxonomic data can be found on World Flora Online, id: wfo-4000026383.

Statistics

Synonyms of Nuphar

Name Author Protologue Nomenclator WFO link
Nenuphar Link Enum. Hort. Berol. Alt. 2: 70 (1822) wfo-4000025588
Nymphona Bubani Fl. Pyren. 3: 260 (1901) wfo-4000026426
Nymphozanthus Rich. Démonstr. Bot. : 63, 68, 103 (1808) wfo-4000026427
Ropalon Raf. New Fl. 2: 17 (1837) wfo-4000033462

${ subTaxaHeading.fullName } in Nuphar ( ${subTaxaPageIsLoading?'loading':'showing'} ${ subTaxaHeading.shortName } ${getRangeFirst(subTaxaPaging)} to ${getRangeLast(subTaxaPaging)} of ${ subTaxaPaging.totalItems })

Name Author Protologue Nomenclator WFO link

Unplaced Names ( ${unplacedPageIsLoading?'loading':'showing'} unplaced names ${getRangeFirst(unplacedPaging)} to ${getRangeLast(unplacedPaging)} of ${ unplacedPaging.totalItems })

These names are not yet placed in the taxonomy, but may be associated with Nuphar:

Name Author Protologue Nomenclator WFO link
`, data() { const wfoCategories = [ "synonym", "accepted", "unplaced", "null", "species", "subspecies", "variety", "subvariety", "subform", "form", "subseries", "series", "subsection", "section", "subgenus", "genus", "subtribe", "tribe", "supertribe", "subfamily", "family", "suborder", "order", "superorder", "subclass", "class", "phylum", "subkingdom", "kingdom", "code", "unranked", "depricated", ]; // Recommended approach: Set domain for consistent colors, with fallback for new ranks const rankColorScale = d3.scaleOrdinal() .domain(wfoCategories) .range(d3.schemePaired) .unknown(() => { // For unknown ranks, assign the next available color from schemePaired const usedColors = wfoCategories.length; const schemeLength = d3.schemePaired.length; const nextColorIndex = usedColors % schemeLength; return d3.schemePaired[nextColorIndex]; }); return { pieLayout: d3.pie().value(d => d.value).sortValues(null), pickedStat: null, pickedGraph: 'species', colours: rankColorScale, _isInitialLoad: true // Flag to track initial load } }, computed: { stats() { return this.groupedStats[this.pickedGraph] || [] }, outerRadius() { return Math.min(this.svgWidth, this.svgHeight) / 2 - 20 }, innerRadius() { return this.outerRadius * .45 }, arc() { return d3.arc().outerRadius(this.outerRadius).innerRadius(this.innerRadius).cornerRadius(4) }, pieData() { return this.stats.length ? this.pieLayout(this.stats) : [] }, currentTotalValues() { return this.stats.reduce((acc, s) => acc + s.value, 0) }, centreGroup() { return `translate(${this.svgWidth/2}, ${this.svgHeight/2})` }, isRankTypeStat() { return this.pickedGraph === 'rank' || this.pickedGraph === 'accepted'; } }, watch: { pickedStat() { this.updateActiveClass() }, pickedGraph() { this.updatePie() this._isInitialLoad = false; } }, mounted() { this.setupSvg() this.updatePie(true); }, methods: { setupSvg() { const svg = d3.select(this.$refs.svgContainer); svg.selectAll('*').remove(); // Ensure a clean slate // Create the main group 'g' only once this._svgGroup = svg .attr('width', this.svgWidth) .attr('height', this.svgHeight) .attr('class', "container") .append('g') .attr('class', 'pies') .attr('transform', this.centreGroup) }, updateActiveClass() { if (this._pathElements) { this._pathElements.attr('class', d => d.data.id === this.pickedStat ? 'active' : ''); } }, updatePie(isInitial = false) { const self = this; const paths = this._svgGroup.selectAll('path') .data(this.pieData, d => d.data.label); const durationValue = isInitial ? 700 : 800; // EXIT selection paths.exit() .transition() .duration(durationValue) .attrTween('d', function(d) { // 'this._current' holds the *last* known angular state of this element before it exited. const start = this._current || d; // Use its last known position as the start of the exit animation const end = { startAngle: start.startAngle, // Collapse to its own START angle endAngle: start.startAngle // Making start and end angles equal creates a zero-width arc at the start edge }; const interpolate = d3.interpolate(start, end); return t => self.arc(interpolate(t)); }) .remove(); // ENTER selection const enter = paths.enter() .append('path') .each(function(d) { // Initialize _current for new elements. // If initial load, they start from (0,0) and tween. // If not initial, they appear at their start angle and tween in from there. this._current = isInitial ? { startAngle: 0, endAngle: 0 } : { startAngle: d.startAngle, endAngle: d.startAngle }; }) .on('mouseover', (event, d) => { self.pickedStat = d.data.id; }) .on('mouseout', () => { self.pickedStat = null; }); // MERGE (Enter + Update) selection this._pathElements = enter.merge(paths); // Animate all paths (new and existing) this._pathElements .attr('fill', (d, i) => { return self.colours(d.data.label); }) .transition() .duration(durationValue) .attrTween('d', function(d) { // Use the _current state (from previous transition or initial setup) // as the starting point for interpolation. const previous = this._current; const interpolate = d3.interpolate(previous, d); // Crucially, update _current to the *target* state for the next transition. this._current = d; return t => self.arc(interpolate(t)); }) }, percentage(value) { const total = this.currentTotalValues const percentage = (value / total) * 100 return percentage < 1 ? Math.round(percentage * 10) / 10 : Math.round(percentage) }, totalForStatsWithKey(key) { const stats = this.groupedStats[key] || [] return stats.length ? stats.reduce((acc, s) => acc + s.value, 0) : 0 }, formatNumber(amount) { if (isNaN(amount)) return '' const sign = amount < 0 ? '-' : '' const abs = Math.abs(amount) return sign + abs.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") }, tweenPie(b) { const i = d3.interpolate({ startAngle: 0, endAngle: 0 }, b) return t => this.arc(i(t)) }, capitalize(s) { if (!s) return '' return s.charAt(0).toUpperCase() + s.slice(1) }, } }) var vm = new Vue({ el: "#el", delimiters: ["${", "}"], data: function () { const urlParams = new URLSearchParams(window.location.search); const subTaxaInitalPage = parseInt(urlParams.get('subTaxaPage')); const unplacedInitalPage = parseInt(urlParams.get('unplacedPage')); const perPage = 10; return { groupedStats: groupedStats, hideSyns: false, children: children, unplaced: unplaced, totalSyns: totalSyns, subTaxaPageIsLoading: false, unplacedPageIsLoading: false, subTaxaPaging: this.createPaging(partsCount, perPage, (subTaxaInitalPage && subTaxaInitalPage > 0) ? subTaxaInitalPage : 1, partsCount), // totalItems, perPage, currentPage unplacedPaging: this.createPaging(unplacedCount, perPage, (unplacedInitalPage && unplacedInitalPage > 0) ? unplacedInitalPage : 1, unplacedCount), // totalItems, perPage, currentPage, allRanks: typeof allRanks !== "undefined" ? allRanks : [], // assign global safely }; }, created() { }, mounted() { this.init() }, methods: { init: function () { //on page load check the url for any info const urlParams = new URLSearchParams(window.location.search); this.hideSyns = (urlParams.get('hide_syns') === 'true'); }, getTaxonUri: function (taxon) { var url = "/taxon/"; url += taxon.id; if(taxon.id.length < 22) { url += '-' + latestClassification.id } return url }, getNomenclature: function (taxon) { var uir = ""; var kind; var ipniIdentifier = taxon.identifiersOther.filter(nomenclature => nomenclature.kind === 'ipni'); var tropicosIdentifier = taxon.identifiersOther.filter(nomenclature => nomenclature.kind === 'tropicos'); if (ipniIdentifier.length) { uir = `https://www.ipni.org/n/${ipniIdentifier[0].value}`.trim() kind = 'ipni'; } else if (tropicosIdentifier.length) { uir = `https://www.tropicos.org/name/${tropicosIdentifier[0].value}`.trim() kind = 'tropicos'; } return { kind: kind, uir: uir} }, createPaging: function (totalItems, perPage, currentPage) { return { totalItems: totalItems, perPage: perPage, currentPage: currentPage || 1, } }, getOffset: function (paging) { return (paging.perPage * paging.currentPage) - paging.perPage; }, getRangeFirst: function (paging) { return this.getOffset(paging) + 1; }, getRangeLast: function (paging) { return Math.min(this.getOffset(paging) + paging.perPage, paging.totalItems); }, isSecondLastPage: function (paging) { return paging.currentPage === this.totalPages(paging) - 1; }, isLastPage: function (paging) { return paging.currentPage >= this.totalPages(paging); }, remainingItemsCount: function (paging) { return paging.totalItems % paging.perPage || paging.perPage; }, totalPages: function (paging) { if (!paging.perPage) return 1; // avoid div by zero return Math.ceil(paging.totalItems / paging.perPage); }, prevPage: function (paging) { if (paging.currentPage > 1) paging.currentPage--; }, nextPage: function (paging) { if (!this.isLastPage(paging)) paging.currentPage++; }, async performSubTaxaQuery(offset, limit) { const query = `query { taxonConceptById(taxonId: "${taxonId}") { id children: hasPart(offset: ${offset}, limit: ${limit}) { id title hasName { ...taxonFields } hasSynonym { ...taxonFields } } } } fragment taxonFields on TaxonName { id title nameString fullNameStringHtml fullNameStringNoAuthorsHtml fullNameStringNoAuthorsPlain fullNameStringPlain speciesString genusString authorsString authorsStringHtml citationMicro classificationId comment nomenclaturalStatus rank role stableUri identifiersOther { kind value } }`; const response = await this.fetchItems(JSON.stringify({ query })); if (!response || !response.data || !response.data.taxonConceptById) { console.warn("Invalid response from GraphQL:", response); return []; } return response.data.taxonConceptById.children; }, async performUplacedItemsQuery(offset, limit) { console.log("perfoming Query!"); const query = `query { taxonConceptById(taxonId: "${taxonId}") { id hasUnplacedName(offset: ${offset} , limit: ${limit}) { ...taxonFields } } } fragment taxonFields on TaxonName { id title nameString fullNameStringHtml fullNameStringNoAuthorsHtml fullNameStringNoAuthorsPlain fullNameStringPlain speciesString genusString authorsString authorsStringHtml citationMicro classificationId comment nomenclaturalStatus rank role stableUri identifiersOther { kind value } }`; const response = await this.fetchItems(JSON.stringify({ query })); console.log(response); if (!response || !response.data || !response.data.taxonConceptById) { console.warn("Invalid response from GraphQL:", response); return []; } return response.data.taxonConceptById.hasUnplacedName; }, fetchItems: async function (query) { let opts = { method: "POST", headers: {}, body: query }; const response = await fetch(requestURL, opts); const responseJson = await response.json(); return responseJson }, updateUrlParam(paramName, value) { const urlParams = new URLSearchParams(window.location.search); urlParams.set(paramName, value); history.pushState(null, null, "?" + urlParams.toString()); }, capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); }, }, watch: { hideSyns: function () { //if checkbox changes, also update the url const urlParams = new URLSearchParams(window.location.search); urlParams.set('hide_syns', this.hideSyns); history.pushState(null, null, "?"+urlParams.toString()); }, 'subTaxaPaging.currentPage': async function (newPage) { // Update URL for subtaxa page this.updateUrlParam('subTaxaPage', newPage); // Load new subtaxa data this.subTaxaPageIsLoading = true; this.children = await this.performSubTaxaQuery( this.getOffset(this.subTaxaPaging), this.subTaxaPaging.perPage ); this.subTaxaPageIsLoading = false; }, 'unplacedPaging.currentPage': async function (newPage) { //if page changes, also update the url // Update URL for unplaced taxa page this.updateUrlParam('unplacedPage', newPage); // Load new unplaced data this.unplacedPageIsLoading = true; this.unplaced = await this.performUplacedItemsQuery( this.getOffset(this.unplacedPaging), this.unplacedPaging.perPage ); this.unplacedPageIsLoading = false; }, }, computed: { currentNoOfSyns() { var hits = this.children.reduce((accumulator, element) => accumulator + element.hasSynonym.length, 0); return hits }, subTaxaHeading() { if (!this.children || this.children.length === 0) { return { shortName: "subtaxa", fullName: "Subtaxa" }; } // Count how many children per rank const rankCounts = {}; this.children.forEach(child => { const rank = child.hasName?.rank; if (rank) rankCounts[rank] = (rankCounts[rank] || 0) + 1; }); const uniqueRanks = Object.keys(rankCounts); // Case 1: only one rank used if (uniqueRanks.length === 1) { const rankId = uniqueRanks[0]; const count = rankCounts[rankId]; const rank = this.allRanks?.find(r => r.id === rankId); const singular = rank?.id || rankId; const plural = rank?.plural || (rankId + "s"); return { shortName: count === 1 ? singular.toLowerCase() : plural.toLowerCase(), fullName: count === 1 ? this.capitalize(singular) : this.capitalize(plural) }; } // Case 2: mixed ranks — lowercase in shortName and fullName const labels = uniqueRanks.map(rankId => { const count = rankCounts[rankId]; const rank = this.allRanks?.find(r => r.id === rankId); const label = count === 1 ? (rank?.id || rankId) : (rank?.plural || (rankId + "s")); return label.toLowerCase(); }); return { shortName: "subtaxa", fullName: `Subtaxa (${labels.join(", ")})` }; }, hideNomenclator() { return !this.children.some(child => { // Check the main taxonConcept const hasMain = Array.isArray(child.hasName?.identifiersOther) && child.hasName.identifiersOther.some(id => id && ["ipni", "tropicos"].includes(id.kind) ); // Check synonyms if visible const hasSyn = !this.hideSyns && Array.isArray(child.hasSynonym) && child.hasSynonym.some(syn => Array.isArray(syn.identifiersOther) && syn.identifiersOther.some(id => id && ["ipni", "tropicos"].includes(id.kind) ) ); return hasMain || hasSyn; }); } } }) ;