{"id":13426559,"url":"https://github.com/tinker10/D3-Labeler","last_synced_at":"2025-03-15T21:31:22.650Z","repository":{"id":11436813,"uuid":"13892419","full_name":"tinker10/D3-Labeler","owner":"tinker10","description":"D3 plug-in for automatic label placement using simulated annealing.","archived":false,"fork":false,"pushed_at":"2017-11-23T00:35:25.000Z","size":434,"stargazers_count":223,"open_issues_count":10,"forks_count":41,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-10-28T05:12:40.946Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"jashkenas/coffeescript","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tinker10.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-10-26T22:50:48.000Z","updated_at":"2024-10-13T20:59:48.000Z","dependencies_parsed_at":"2022-09-22T22:50:47.063Z","dependency_job_id":null,"html_url":"https://github.com/tinker10/D3-Labeler","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinker10%2FD3-Labeler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinker10%2FD3-Labeler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinker10%2FD3-Labeler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinker10%2FD3-Labeler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tinker10","download_url":"https://codeload.github.com/tinker10/D3-Labeler/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243792401,"owners_count":20348638,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T00:01:37.879Z","updated_at":"2025-03-15T21:31:22.339Z","avatar_url":"https://github.com/tinker10.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Utils"],"sub_categories":[],"readme":"D3-Labeler\n=========\n\nA D3 plug-in for automatic label placement using simulated annealing that easily incorporates into existing D3 code, with syntax mirroring other D3 layouts. \n\n[View a demo here](http://tinker10.github.io/D3-Labeler/). \n\nInstallation\n------------\n\nDownload \u003ci\u003elabeler.js\u003c/i\u003e. Include the plug-in within the relevant .html file with:\n```html\n\u003cscript src=\"labeler.js\"\u003e\u003c/script\u003e\n```\n\nComponents of a labeling problem\n--------------------------------\n\n![label](label.png)\n\nEach *label* corresponds to an *anchor point*. A *leader line* may be used to help with the correspondence between the *label* and *anchor point*. None of the elements may cross the *graph boundary*.\n\nUsage\n-----------------\n\nTo automatically place labels, users declare a labeler (simulated annealing) layout, input label and anchor positions, the figure boundaries, and the number of Monte Carlo sweeps for simulated annealing. The general pattern is as follows:\n```javascript\nvar labels = d3.labeler()\n               .label(label_array)\n               .anchor(anchor_array)\n               .width(w)\n               .height(h)\n               .start(nsweeps);\n```\nThe default settings are: \u003ci\u003ew\u003c/i\u003e = 1, \u003ci\u003eh\u003c/i\u003e = 1, and \u003ci\u003ensweeps\u003c/i\u003e = 1000. The default \u003ci\u003elabel_array\u003c/i\u003e and \u003ci\u003eanchor_array\u003c/i\u003e are empty arrays. Here we describe each term in more detail.\n\nd3.\u003cb\u003elabeler\u003c/b\u003e()\n\nStart by declaring a labeling layout, the same as declaring any other D3 layout.\n\nlabeler.\u003cb\u003elabel\u003c/b\u003e([\u003ci\u003elabel_array\u003c/i\u003e])\n\nEach label has the following attributes:\n\n* x - the *x*-coordinate of the label.\n* y - the *y*-coordinate of the label.\n* width - the *width* of the label (approximating the label as a rectangle).\n* height - the *height* of the label (same approximation).\n* name - the label text.\n\n```javascript\nvar label_array = [{x: 10.2, y: 17.1, name: \"Node 3\", width: 18.0, height: 7.2}, ...]\n```\n\nNote that width and height can be easily measured using the SVG getBBox() method. The dimensions are used to calculate overlaps.\n\n```javascript\nvar index = 0;\nlabels.each(function() {\n   label_array[index].width = this.getBBox().width;\n   label_array[index].height = this.getBBox().height;\n   index += 1;\n});\n```\n\nlabeler.\u003cb\u003eanchor\u003c/b\u003e([\u003ci\u003eanchor_array\u003c/i\u003e])\n\nEach anchor has the following attributes:\n\n* x - the *x*-coordinate of the anchor.\n* y - the *y*-coordinate of the anchor.\n* r - the anchor radius (assuming anchor is a circle). \n\n```javascript\nvar anchor_array = [{x: 5.3, y: 12.0, r: 7}, {x: 16.8, y: 23.5, r: 7}, ...]\n```\n\nlabeler.\u003cb\u003ewidth\u003c/b\u003e(\u003ci\u003ew\u003c/i\u003e)\n\nlabeler.\u003cb\u003eheight\u003c/b\u003e(\u003ci\u003eh\u003c/i\u003e)\n\nThe width and height are used to set the boundary conditions so that labels do not go outside the width and height of the figure. More specifically, Monte Carlo moves in which the labels cross the boundaries are rejected. If they are not specified, both the width and height default to 1. \n\nlabeler.\u003cb\u003estart\u003c/b\u003e(\u003ci\u003ensweeps\u003c/i\u003e)\n\nFinally, we specify the number of Monte Carlo sweeps for the optimization and run the simulated annealing procedure. The default for \u003ci\u003ensweeps\u003c/i\u003e is 1000. Note that one Monte Carlo sweep means that on average, each label is translated or rotated once. To obtain the actual number of Monte Carlo steps taken, multiply the number of sweeps by the number of labels.\n\nlabeler.\u003cb\u003ealt_energy\u003c/b\u003e(\u003ci\u003euser_defined_energy\u003c/i\u003e)\n\nThis function is constructed for \u003ci\u003eexpert users\u003c/i\u003e. The quality of the configuration is closely related to the energy function. The default energy function includes general labeling preferences (details below) and is suggested for most users. However, a user may wish to define his or her own energy function to suit individual preferences. \n```javascript\nnew_energy_function = function(index, label_array, anchor_array) {\n    var ener = 0;\n    // insert user-defined interaction energies here\n    return ener;\n}\n```\nThe newly constructed function must take as input an integer \u003ci\u003eindex\u003c/i\u003e, an array of labels \u003ci\u003elabel_array\u003c/i\u003e, and an array of anchors \u003ci\u003eanchor_array\u003c/i\u003e. This function must also return an energy term that should correspond to the energy of a particular label, namely \u003ci\u003elabel_array[index]\u003c/i\u003e. One may wish calculate an energy of interaction for \u003ci\u003elabel_array[index]\u003c/i\u003e with all other labels and anchors. \n\nlabeler.\u003cb\u003ealt_schedule\u003c/b\u003e(\u003ci\u003euser_defined_schedule\u003c/i\u003e)\n\nSimilarly, an expert user may wish to include a custom cooling schedule used in the simulated annealing procedure. The default cooling schedule is linear. \n```javascript\nnew_cooling_schedule = function(currT, initialT, nsweeps) {\n    // insert user-defined schedule here\n    return updatedT;\n}\n```\nThis function takes as input the current simulation temperature \u003ci\u003ecurrT\u003c/i\u003e, the initial temperature \u003ci\u003einitialT\u003c/i\u003e, and the total number of sweeps \u003ci\u003ensweeps\u003c/i\u003e and returns the updated temperature \u003ci\u003eupdatedT\u003c/i\u003e. The user defined functions can be included as follows:\n\n```javascript\nvar labels = d3.labeler()\n               .label(label_array)\n               .anchor(anchor_array)\n               .width(w)\n               .height(h)\n               .alt_energy(new_energy_function)\n               .alt_schedule(new_cooling_schedule)\n               .start(nsweeps);\n```\n\n\nDefault energy function details\n-------------------------------\n\nIn order to distinguish between the quality of different configurations in our search space, we need construct a function which takes as input a label configuration and outputs a score indicating the quality of the placements. In a labeling problem, the inputs are themselves functions of various parameters such as the amount of overlaps, distances between labels and their corresponding anchor points, and various stylistic preferences. This function, often an energy (also called cost or objective) function, is what we need to optimize. The default energy function includes penalties for:\n\n* Label-label overlaps\n* Label-anchor overlaps\n* Labels far from the corresponding anchor\n* Leader line intersections\n* Poorly oriented labels\n\nAuthor\n------\n* Evan Wang (\u003cevan.wang@berkeley.edu\u003e)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinker10%2FD3-Labeler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftinker10%2FD3-Labeler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinker10%2FD3-Labeler/lists"}