Extension:Graph/en
<translate> Warning:</translate> <translate> The code or configuration described here poses a major security risk.</translate> <translate> Site administrators:</translate> <translate> You are advised against using it until this security issue is resolved.</translate> <translate> Problem:</translate> <translate> Vulnerable to Cross-site scripting attacks, because it passes user input directly to the browser.</translate> <translate> This may lead to user accounts being hijacked, among other things.</translate> See <translate> task <tvar name=1>T334940</tvar></translate> for more information. <translate> Solution:</translate> <translate> [[<tvar name=1>Special:MyLanguage/Cross-site scripting</tvar>|strictly validate user input and/or apply escaping to all characters]] that have a special meaning in HTML</translate> |
<translate> This extension is currently not actively maintained!</translate> <translate> Although it may still work, any bug reports or feature requests will more than likely be ignored.</translate> <translate> If you are interested in taking on the task of developing and maintaining this extension, [[<tvar name=request>Special:MyLanguage/Gerrit/Privilege policy#Requesting Gerrit privileges</tvar>|you can request repository ownership]].</translate> <translate> As a courtesy, you may want to contact the author.</translate> <translate> You should also remove this template and list yourself as maintaining the extension in the page's <tvar name=extension>{{Extension }}</tvar> infobox.</translate> |
Graph Release status: unmaintained |
|
---|---|
Implementation | Tag , ContentHandler |
Description | Data-driven graphs |
Author(s) | |
MediaWiki | |
License | No license specified |
Download | |
Quarterly downloads | Lua error in Module:Extension at line 172: bad argument #1 to 'inNamespace' (unrecognized namespace name 'skin'). |
Public wikis using | Lua error in Module:Extension at line 172: bad argument #1 to 'inNamespace' (unrecognized namespace name 'skin'). |
Translate the Graph extension if it is available at translatewiki.net | |
Issues | Open tasks · Report a bug |
The Graph extension allows a <graph>
tag to describe data visualizations such as bar charts, pie charts, timelines, and histograms (demo) in a JSON format that renders a Vega-based graph.
General info
Graph extension allows powerful Vega based graphs to be added to the wiki pages. Graphs can be interactive.
The easiest way to add a graph is to use a ready-made template such as {{Graph:Chart}}. These templates hide all Vega complexities. Power users can use the Graph Sandbox to develop graphs. Graph sandbox allows wiki template syntax in addition to JSON. The extension integrates with VisualEditor, providing a simple tool/wizard which generates basic graphs, by entering values directly to the editor.
Useful links
- Vega 2 documentation – restored Vega 2 documentation pages on nyurik/vega/wiki.
- Guide – General recommendations on how to use graphs in wiki.
- Interactive Tutorial – step by step instructions how to build a complex interactive graph from scratch
- Demo page – for many samples and usage tricks.
- TechTalk Video – a WMF tech talk discussing the Graph extension, including a great demo of the Lyra editor (also installed on labs).
- You may also be interested in some of the Vega future capabilities (Keynote by Jeffrey Heer).
- Vega for devs - best place of all Vega resources
- Migrating to Vega 2.0
- Video introduction into interactive Vega
Installation
- Requires JsonConfig extension
- <translate> [[<tvar name=2>Special:ExtensionDistributor/Graph/en</tvar>|Download]] and move the extracted <tvar name=name>
Graph/en
</tvar> folder to your <tvar name=ext>extensions/
</tvar> directory.</translate>
<translate> Developers and code contributors should install the extension [[<tvar name=git>Special:MyLanguage/Download from Git</tvar>|from Git]] instead, using:</translate>cd extensions/
git clone https://gerrit.wikimedia.org/r/mediawiki/extensions/Graph%2Fen - <translate> Add the following code at the bottom of your <tvar name=1>LocalSettings.php </tvar> file:</translate>
wfLoadExtension( 'Graph/en' );
- File:OOjs UI icon check-constructive.svg <translate> Done</translate> – <translate> Navigate to <tvar name=special>Special:Version</tvar> on your wiki to verify that the extension is successfully installed.</translate>
<translate> Vagrant installation:</translate>
- <translate> If using <tvar name=vagrant>Vagrant </tvar>, install with <tvar name=code>
vagrant roles enable graph --provision
</tvar></translate>
Additional config setup
If you are looking to replicate a production environment like en.wiki you will need to complete the following steps:
- Install Scribunto , Imagemap and TemplateStyles , and enable SVG uploads
- If you use vagrant, you can use
vagrant roles enable --provision scribunto imagemap templatestyles svg
- If you use vagrant, you can use
- Import mediawiki.org's Module:Graph, Module:Graph/doc, Template:Nowrap and Template:Nowrap/styles.css (export link)
- Import enwiki's Module:Chart and Module:Chart/Default colors (export link)
- Import the file File:Circle_frame.svg
Debugging graphs and porting graphs from Vega 2 to Vega 5
A sandbox is provided at Special:GraphSandbox that works similar to the Vega graph editor. The MediaWiki tool includes compatibility code that maps older Vega schemas to the currently enabled version. Inserting an old schema in the main text area will print a modified and modernized schema underneath the graph where possible.
Similar to vega.github.io/editor, the Vega object can be inspected via the VEGA_DEBUG
JavaScript global.
See Vega's debugging guide on how to use it.
Migrating schemas from older Vega versions
Previously Graph supported Vega 2. You can paste the JSON of graphs in http://vega.github.io/vega-editor/?mode=vega to see how they previously rendered for comparison with Vega 5.
Special:GraphSandbox (for latest code see the beta cluster version of the sandbox) can be used to map older schemas to new schemas. Copy the old schema into the main textarea and the updated schema will appear in the text area below the graph. Copy the new schema into your code.
Charts examples
See Demo page for many samples and usage tricks.
<graph fallback="" fallbackWidth="">{"legends":[],"scales":[{"type":"band","name":"x","domain":{"data":"chart","field":"x"},"padding":0.2,"range":"width","nice":true},{"type":"linear","name":"y","domain":{"data":"chart","field":"y"},"zero":true,"range":"height","nice":true},{"domain":{"data":"chart","field":"series"},"type":"ordinal","name":"color","range":{"scheme":"category10"}}],"marks":[{"encode":{"hover":{"fill":{"value":"red"}},"update":{"fill":{"scale":"color","field":"series"}},"enter":{"y":{"scale":"y","field":"y"},"x":{"scale":"x","field":"x"},"y2":{"scale":"y","value":0},"width":{"scale":"x","offset":-1,"band":true},"fill":{"scale":"color","field":"series"}}},"type":"rect","from":{"data":"chart"}}],"data":[{"transform":[],"format":{"parse":{"y":"number","x":"number"},"type":"json"},"name":"chart","values":[{"y":10,"series":"y","index":1,"x":1},{"y":12,"series":"y","index":1,"x":2},{"y":6,"series":"y","index":1,"x":3},{"y":14,"series":"y","index":1,"x":4},{"y":2,"series":"y","index":1,"x":5},{"y":10,"series":"y","index":1,"x":6},{"y":7,"series":"y","index":1,"x":7},{"y":9,"series":"y","index":1,"x":8}]}],"height":100,"axes":[{"orient":"bottom","title":"X","encode":{"title":{"fill":{"value":"#54595d"}},"grid":{"stroke":{"value":"#54595d"}},"ticks":{"stroke":{"value":"#54595d"}},"axis":{"strokeWidth":{"value":2},"stroke":{"value":"#54595d"}},"labels":{"fill":{"value":"#54595d"}}},"scale":"x","format":"d","tickMinStep":1,"grid":false},{"orient":"left","encode":{"title":{"fill":{"value":"#54595d"}},"grid":{"stroke":{"value":"#54595d"}},"ticks":{"stroke":{"value":"#54595d"}},"axis":{"strokeWidth":{"value":2},"stroke":{"value":"#54595d"}},"labels":{"fill":{"value":"#54595d"}}},"title":"Y","tickCount":8,"scale":"y","format":"d","tickMinStep":1,"grid":false}],"$schema":"https://vega.github.io/schema/vega/v5.json","width":400} </graph> <graph fallback="" fallbackWidth="">{"legends":[{"orient":"top-right","title":"Legend","labelColor":"#54595d","stroke":"color","titleColor":"#54595d","fill":"color"}],"scales":[{"domain":{"data":"chart","field":"x"},"type":"ordinal","name":"color","range":{"scheme":"category10"}},{"range":[0,50],"type":"linear","name":"r","domain":{"data":"chart","field":"r"}}],"marks":[{"encode":{"enter":{"y":{"value":50},"x":{"value":50},"fill":{"scale":"color","field":"x"}},"update":{"endAngle":{"field":"endAngle"},"innerRadius":{"value":0},"outerRadius":{"scale":"r","value":50,"field":"r"},"startAngle":{"field":"startAngle"},"stroke":{"value":"white"},"fill":{"scale":"color","field":"x"},"strokeWidth":{"value":1}},"hover":{"fill":{"value":"red"}}},"type":"arc","from":{"data":"chart"}},{"encode":{"enter":{"theta":{"signal":"(datum.startAngle + datum.endAngle)/2"},"baseline":{"value":"middle"},"align":{"value":"center"},"text":{"field":"y"},"y":{"value":50},"x":{"value":50},"fontSize":{"value":5},"angle":{"mult":57.29577951308232,"field":"layout_mid"},"radius":{"scale":"r","offset":-15,"field":"r"},"fill":{"value":"white"}}},"type":"text","from":{"data":"chart"}}],"data":[{"transform":[{"type":"pie","field":"y"}],"format":{"parse":{"y":"number","x":"string","r":"number"},"type":"json"},"name":"chart","values":[{"y":100,"x":"A","r":7},{"y":200,"x":"B","r":8},{"y":150,"x":"C","r":9},{"y":300,"x":"D","r":8},{"y":100,"x":"E","r":8},{"y":100,"x":"F","r":9},{"y":150,"x":"G","r":10},{"y":50,"x":"H","r":9},{"y":200,"x":"I","r":5}]}],"height":100,"axes":[],"$schema":"https://vega.github.io/schema/vega/v5.json","width":200} </graph> <graph fallback="" fallbackWidth="">{"legends":[{"title":"Legend","labelColor":"#54595d","stroke":"color","titleColor":"#54595d","fill":"color"}],"scales":[{"type":"linear","name":"x","domain":{"data":"chart","field":"x"},"zero":false,"range":"width","nice":true},{"type":"linear","name":"y","domain":{"data":"chart","field":"y1"},"zero":true,"range":"height","nice":true},{"domain":{"data":"chart","field":"series"},"type":"ordinal","name":"color","range":["seagreen","orchid"]}],"marks":[{"type":"group","marks":[{"encode":{"hover":{"fill":{"value":"red"}},"update":{"fill":{"scale":"color","field":"series"}},"enter":{"y":{"scale":"y","field":"y1"},"interpolate":{"value":"monotone"},"y2":{"scale":"y","field":"y0"},"x":{"scale":"x","field":"x"},"fill":{"scale":"color","field":"series"}}},"type":"area","from":{"data":"facet"}}],"from":{"facet":{"name":"facet","data":"chart","groupby":"series"}}}],"data":[{"transform":[{"field":"y","type":"stack","sort":{"field":"index"},"groupby":["x"]}],"format":{"parse":{"y":"number","x":"number"},"type":"json"},"name":"chart","values":[{"y":10,"series":"y1","index":1,"x":1},{"y":12,"series":"y1","index":1,"x":2},{"y":6,"series":"y1","index":1,"x":3},{"y":14,"series":"y1","index":1,"x":4},{"y":2,"series":"y1","index":1,"x":5},{"y":10,"series":"y1","index":1,"x":6},{"y":2,"series":"y2","index":2,"x":1},{"y":4,"series":"y2","index":2,"x":2},{"y":6,"series":"y2","index":2,"x":3},{"y":8,"series":"y2","index":2,"x":4},{"y":13,"series":"y2","index":2,"x":5},{"y":11,"series":"y2","index":2,"x":6}]}],"height":100,"axes":[{"orient":"bottom","title":"X","encode":{"title":{"fill":{"value":"#54595d"}},"grid":{"stroke":{"value":"#54595d"}},"ticks":{"stroke":{"value":"#54595d"}},"axis":{"strokeWidth":{"value":2},"stroke":{"value":"#54595d"}},"labels":{"fill":{"value":"#54595d"}}},"scale":"x","format":"d","tickMinStep":1,"grid":false},{"orient":"left","encode":{"title":{"fill":{"value":"#54595d"}},"grid":{"stroke":{"value":"#54595d"}},"ticks":{"stroke":{"value":"#54595d"}},"axis":{"strokeWidth":{"value":2},"stroke":{"value":"#54595d"}},"labels":{"fill":{"value":"#54595d"}}},"title":"Y","tickCount":8,"scale":"y","format":"d","tickMinStep":1,"grid":false}],"$schema":"https://vega.github.io/schema/vega/v5.json","width":400} </graph>
<graph mode=interactive title="Historical Fertility Rates"> {
"$schema": "https://vega.github.io/schema/vega/v5.json", "description": "An interactive scatter plot of global health statistics by country and year.", "width": 800, "height": 600, "padding": 5, "data": [ { "name": "gapminder", "url": "https://www.mediawiki.org/wiki/Extension:Graph/data/gapminder-json?action=raw" }, { "name": "clusters", "values": [ {"id": 0, "name": "South Asia"}, {"id": 1, "name": "Europe & Central Asia"}, {"id": 2, "name": "Sub-Saharan Africa"}, {"id": 3, "name": "America"}, {"id": 4, "name": "East Asia & Pacific"}, {"id": 5, "name": "Middle East & North Africa"} ] }, { "name": "country_timeline", "source": "gapminder", "transform": [ {"type": "filter", "expr": "timeline && datum.country == timeline.country"}, {"type": "collect", "sort": {"field": "year"}} ] }, { "name": "thisYear", "source": "gapminder", "transform": [ {"type": "filter", "expr": "datum.year == currentYear"} ] }, { "name": "prevYear", "source": "gapminder", "transform": [ {"type": "filter", "expr": "datum.year == currentYear - stepYear"} ] }, { "name": "nextYear", "source": "gapminder", "transform": [ {"type": "filter", "expr": "datum.year == currentYear + stepYear"} ] }, { "name": "countries", "source": "gapminder", "transform": [ {"type": "aggregate", "groupby": ["country"]} ] }, { "name": "interpolate", "source": "countries", "transform": [ { "type": "lookup", "from": "thisYear", "key": "country", "fields": ["country"], "as": ["this"], "default": {} }, { "type": "lookup", "from": "prevYear", "key": "country", "fields": ["country"], "as": ["prev"], "default": {} }, { "type": "lookup", "from": "nextYear", "key": "country", "fields": ["country"], "as": ["next"], "default": {} }, { "type": "formula", "as": "target_fertility", "expr": "interYear > currentYear ? datum.next.fertility : (datum.prev.fertility||datum.this.fertility)" }, { "type": "formula", "as": "target_life_expect", "expr": "interYear > currentYear ? datum.next.life_expect : (datum.prev.life_expect||datum.this.life_expect)" }, { "type": "formula", "as": "inter_fertility", "expr": "interYear==2000 ? datum.this.fertility : datum.this.fertility + (datum.target_fertility-datum.this.fertility) * abs(interYear-datum.this.year)/5" }, { "type": "formula", "as": "inter_life_expect", "expr": "interYear==2000 ? datum.this.life_expect : datum.this.life_expect + (datum.target_life_expect-datum.this.life_expect) * abs(interYear-datum.this.year)/5" } ] }, { "name": "trackCountries", "on": [ {"trigger": "active", "toggle": "{country: active.country}"} ] } ], "signals": [ { "name": "minYear", "value": 1955 }, { "name": "maxYear", "value": 2005 }, { "name": "stepYear", "value": 5 }, { "name": "active", "value": {}, "on": [ {"events": "@point:mousedown, @point:touchstart", "update": "datum"}, {"events": "window:mouseup, window:touchend", "update": "{}"} ] }, { "name": "isActive", "update": "active.country" }, { "name": "timeline", "value": {}, "on": [ {"events": "@point:mouseover", "update": "isActive ? active : datum"}, {"events": "@point:mouseout", "update": "active"}, {"events": {"signal": "active"}, "update": "active"} ] }, { "name": "tX", "on": [{ "events": "mousemove!, touchmove!", "update": "isActive ? scale('x', active.this.fertility) : tX" }] }, { "name": "tY", "on": [{ "events": "mousemove, touchmove", "update": "isActive ? scale('y', active.this.life_expect) : tY" }] }, { "name": "pX", "on": [{ "events": "mousemove, touchmove", "update": "isActive ? scale('x', active.prev.fertility) : pX" }] }, { "name": "pY", "on": [{ "events": "mousemove, touchmove", "update": "isActive ? scale('y', active.prev.life_expect) : pY" }] }, { "name": "nX", "on": [{ "events": "mousemove, touchmove", "update": "isActive ? scale('x', active.next.fertility) : nX" }] }, { "name": "nY", "on": [{ "events": "mousemove, touchmove", "update": "isActive ? scale('y', active.next.life_expect) : nY" }] }, { "name": "thisDist", "value": 0, "on":[{ "events": "mousemove, touchmove", "update": "isActive ? sqrt(pow(x()-tX, 2) + pow(y()-tY, 2)) : thisDist" }] }, { "name": "prevDist", "value": 0, "on":[{ "events": "mousemove, touchmove", "update": "isActive ? sqrt(pow(x()-pX, 2) + pow(y()-pY, 2)): prevDist" }] }, { "name": "nextDist", "value": 0, "on":[{ "events": "mousemove, touchmove", "update": "isActive ? sqrt(pow(x()-nX, 2) + pow(y()-nY, 2)) : nextDist" }] }, { "name": "prevScore", "value": 0, "on": [{ "events": "mousemove, touchmove", "update": "isActive ? ((pX-tX) * (x()-tX) + (pY-tY) * (y()-tY))/prevDist || -999999 : prevScore" }] }, { "name": "nextScore", "value": 0, "on": [{ "events": "mousemove, touchmove", "update": "isActive ? ((nX-tX) * (x()-tX) + (nY-tY) * (y()-tY))/nextDist || -999999 : nextScore" }] }, { "name": "interYear", "value": 1980, "on": [{ "events": "mousemove, touchmove", "update": "isActive ? (min(maxYear, currentYear+5, max(minYear, currentYear-5, prevScore > nextScore ? (currentYear - 2.5*prevScore/sqrt(pow(pX-tX, 2) + pow(pY-tY, 2))) : (currentYear + 2.5*nextScore/sqrt(pow(nX-tX, 2) + pow(nY-tY, 2)))))) : interYear" }] }, { "name": "currentYear", "value": 1980, "on":[{ "events": "mousemove, touchmove", "update": "isActive ? (min(maxYear, max(minYear, prevScore > nextScore ? (thisDist < prevDist ? currentYear : currentYear-5) : (thisDist < nextDist ? currentYear : currentYear+5)))) : currentYear" }] } ], "scales": [ { "name": "x", "type": "linear", "nice": true, "domain": {"data": "gapminder", "field": "fertility"}, "range": "width" }, { "name": "y", "type": "linear", "nice": true, "zero": false, "domain": {"data": "gapminder", "field": "life_expect"}, "range": "height" }, { "name": "color", "type": "ordinal", "domain": {"data": "gapminder", "field": "cluster"}, "range": "category" }, { "name": "label", "type": "ordinal", "domain": {"data": "clusters", "field": "id"}, "range": {"data": "clusters", "field": "name"} } ], "axes": [ { "title": "Fertility", "orient": "bottom", "scale": "x", "grid": true, "tickCount": 5 }, { "title": "Life Expectancy", "orient": "left", "scale": "y", "grid": true, "tickCount": 5 } ], "legends": [ { "fill": "color", "title": "Region", "orient": "right", "encode": { "symbols": { "enter": { "fillOpacity": {"value": 0.5} } }, "labels": { "update": { "text": {"scale": "label", "field": "value"} } } } } ], "marks": [ { "type": "text", "encode": { "update": { "text": {"signal": "currentYear"}, "x": {"value": 300}, "y": {"value": 300}, "fill": {"value": "grey"}, "fillOpacity": {"value": 0.25}, "fontSize": {"value": 100} } } }, { "type": "text", "from": {"data": "country_timeline"}, "interactive": false, "encode": { "enter": { "x": {"scale": "x", "field": "fertility", "offset": 5}, "y": {"scale": "y", "field": "life_expect"}, "fill": {"value": "#555"}, "fillOpacity": {"value": 0.6}, "text": {"field": "year"} } } }, { "type": "line", "from": {"data": "country_timeline"}, "encode": { "update": { "x": {"scale": "x", "field": "fertility"}, "y": {"scale": "y", "field": "life_expect"}, "stroke": {"value": "#bbb"}, "strokeWidth": {"value": 5}, "strokeOpacity": {"value": 0.5} } } }, { "name": "point", "type": "symbol", "from": {"data": "interpolate"}, "encode": { "enter": { "fill": {"scale": "color", "field": "this.cluster"}, "size": {"value": 150} }, "update": { "x": {"scale": "x", "field": "inter_fertility"}, "y": {"scale": "y", "field": "inter_life_expect"}, "fillOpacity": [ { "test": "datum.country==timeline.country || indata('trackCountries', 'country', datum.country)", "value": 1 }, {"value": 0.5} ] } } }, { "type": "text", "from": {"data": "interpolate"}, "interactive": false, "encode": { "enter": { "fill": {"value": "#333"}, "fontSize": {"value": 14}, "fontWeight": {"value": "bold"}, "text": {"field": "country"}, "align": {"value": "center"}, "baseline": {"value": "bottom"} }, "update": { "x": {"scale": "x", "field": "inter_fertility"}, "y": {"scale": "y", "field": "inter_life_expect", "offset": -7}, "fillOpacity": [ { "test": "datum.country==timeline.country || indata('trackCountries', 'country', datum.country)", "value": 0.8 }, {"value": 0} ] } } } ]
} </graph>
User defined fallback
When using client side rendering, it is possible to use Wikimedia Commons to provide a static fallback image to noscript
users.
This is a temporary solution until a new service is put in place to provide server side rendering.
The user must first upload the static graph to Wikimedia Commons.
Fallback images have two variables fallback
and fallbackWidth
.
fallback
relates to a Wikimedia Commons filename.
fallbackWidth
is the fallback images width in pixels.
These variables are pass through the graph in the following way:
<graph fallback="Graph test seddon.png" fallbackWidth=450>
Where lua modules are used such as Module:Graph then these variables can be provided via the tag function. If Template:Graph:Chart were adapted, it would look like this:
{{safesubst:#tag:graph|{{safesubst:#invoke:Graph|chartWrapper}} | fallback = {{{fallback|''}}} | fallbackWidth= {{{fallbackWidth|''}}} }}
It would then be utilised in a template in the following manner:
{{Graph:Chart|width=400|height=100|xAxisTitle=X|yAxisTitle=Y
|type=rect|x=1,2,3,4,5,6,7,8|y=10,12,6,14,2,10,7,9|fallback=Graph test seddon.png|fallbackWidth=450}}
If a fallbackWidth isn't provided but an image is defined then the extension will derive the width from the provided graph width. The reason for this is there is frequently a difference in the rendered image width and the actual image width.
{{Graph:Chart|width=400|height=100|xAxisTitle=X|yAxisTitle=Y
|type=rect|x=1,2,3,4,5,6,7,8|y=10,12,6,14,2,10,7,9|fallback=Graph test seddon.png}}
External data
HTTP(S) protocol cannot be used to get data for the graph.
Instead, use one of the custom wiki protocols like wikiraw:
, wikiapi:
, and others.
Graph extension uses the GraphAllowedDomains
setting to control how these protocols are resolved:
Note that because queries rely on the structure of wikibase items, they may suddenly stop working if the underlying data is edited and changes, as it may yield incomplete, empty or invalid data that can't be used to create a graph.
In these cases the graph will end up empty (see phab:T168601).
$wgGraphAllowedDomains = [
# http + https keys lists all of the domains allowed for the external data access.
# Any domain listed here automatically permits all subdomains as well.
# Custom protocols like 'wikiraw' use it to determine which protocol to use.
# This way wikiraw://en.wikipedia.org/Page will be an api request to https://en.wikipedia.org/w/api.php?action=query&titles=Page&...
'https' => [ 'wikipedia.org', 'wikimedia.org', ... ],
'http' => [ 'wmflabs.org', ... ],
# list of domains allowed for the wikirawupload: protocol access.
# Exact match only, no subdomains.
'wikirawupload' => [ 'upload.wikimedia.org' ],
# same as wikirawupload but for Wikidata Sparql queries
'wikidatasparql' => [ 'query.wikidata.org' ],
];
Internals
When parsing, the Graph extension expands all template parameters/expressions, and stores the complete graph definitions in the ParserOutput, using graph hashes for IDs.
The graph extension adds HTML to the page where graphs should go, a <div>
with a graph-id as the attribute.
Sample:
<div class="mw-graph" data-graph-id="72edc224f0a10b343c1e84f63dbfc97cac9bc957">
</div>
The Graph extension adds an ext.graph
ResourceLoader JavaScript module to the page that includes the Vega library, and puts the JSON of graph definitions into a JavaScript mediawiki.config
variable named wgGraphSpecs
.
Once the client has loaded this module, the Vega JavaScript library populates each <div>
with an HTML canvas and draws the graph in it, replacing the static image.
Security features
<graph>
can be configured to disallow referencing untrusted data sources (e.g. Wikimedia only allows data from the Wikimedia sites).
License
Vega library is distributed under a modified BSD license acceptable under for us to use.
“ | This appears to be a copy of the BSD license, with some minor (acceptable) modifications. It's not a problem for us to use it, although ideally they would not make changes like this to the license. It's better if people do not make these changes to their license, to avoid confusion (like this) about whether the license is safe for open-source use. | ” |
—Stephen LaPorte |
Configuration
wgGraphAllowedDomains
See the section on external data.
VisualEditor module
Since summer 2015, the Graph extension also comes with a module (ext.graph.VisualEditor) which enables graph editing within VisualEditor.
This module was a result of a Google Summer of Code 2015 project. See phab:T89287 for more details.
This module allows users to see graphs within VisualEditor, as opposed to alien extension nodes. Furthermore, users can open up a dialog to edit a graph's type, data and padding. The UI also offers a way to edit a graph's raw JSON specification within VE without having to switch to the classic wikitext editor, in case more advanced users want to tweak settings not supported by the UI.
This first step serves as a stepping stone for many possibilities with graph editing within VisualEditor, and there are a lot of ways in which the module can be improved and expanded.
Troubleshooting broken graphs
Errors with graphs will be logged in the developer console.
Error: Bad constructor arguments (phab:T277906)
To fix: Replace filepath:Earthmap1000x500compac.jpg with filepath:Earthmap1000x500.jpg
TypeError: undefined is not an object (evaluating 'datum.firstYear.value')
To fix: Make sure you have not set default as null
See also
- Diagram extensions
- Plotly — The open source JavaScript graphing library (with 3d charting capabilities)
- D3 — Data-Driven Documents
File:OOjs UI icon information-progressive.svg | <translate> This extension is included in the following wiki farms/hosts and/or packages:</translate>
<translate> This is not an authoritative list.</translate> <translate> Some wiki farms/hosts and/or packages may contain this extension even if they are not listed here.</translate> <translate> Always check with your wiki farms/hosts or bundle to confirm.</translate> |
- Pages with script errors
- Pages with syntax highlighting errors
- Pages with broken file links
- Extensions with XSS vulnerabilities/en
- Unmaintained extensions/en
- Tag extensions/en
- ContentHandler extensions/en
- Extensions without MediaWiki version
- Extensions with no license specified/en
- Extensions in Wikimedia version control/en
- All extensions/en
- Extensions not in ExtensionJson
- Graph extensions/en
- Extensions with VisualEditor support/en
- Discovery/en