Extension:Chart/Transforms/fr
Pour maximiser la capacité des éditeurs et éditrices à travailler avec des ensembles de données complexes, nous avons étendu Extension:Chart afin que les ensembles de données tabulaires puissent être transformés, modifiés, découpés ou générés à partir de code Lua, en utilisant le même moteur sous-jacent Extension:Scribunto qui pilote les modèles complexes avec la fonction d’analyseur syntaxique à 3$.
Chart format descriptions can include a transform
which refers to a Lua Module:
page and function, and passes some key-value parameters as an associative array.
L’ensemble de données source est traduit en objets Lua et transmis, avec les arguments, et le transformateur peut modifier ou remplacer l’ensemble des données tabulaires comme il le souhaite.
Le chargement de modules de données supplémentaires est enregistré à des fins d’invalidation du cache, de sorte qu’une modification du module référencé ou de toute page de données entraînera le réaffichage des pages avec le graphique.
Developer internals
See Extension:JsonConfig/Transforms for internals documentation or to add related support to another data type / output method.
Editor usage
Invocation
Actuellement, les transformations pour les graphiques doivent être configurées dans la page de description du format Data:.chart
, comme suit :
{
"license": "CC0-1.0",
"version": 1,
"type": "bar",
"xAxis": {
"title": { "en": "Day" }
},
"yAxis": {
"title": { "en": "Temperature" }
},
"transform": {
"module": "Weekly average temperature chart",
"function": "convert_temps",
"args": {
"units": "C"
}
},
"source": "Sample weekly temperature dataset.tab"
}
Les paramètres module
et function
sont équivalents aux deux premiers paramètres du {{#invoke:}} de Scribunto et renvoient à la page Module:
avec le code source et la fonction spécifique à invoquer.
'“'Important:” comme les pages Data:
, le code Lua Module:
sera chargé et exécuté dans le contexte du magasin de données centralisé wiki (par exemple, Wikimedia Commons).
Cela signifie que, quel que soit le wiki sur lequel vous effectuez le rendu, vous exécuterez le code dans un endroit centralisé -- les modules peuvent donc être partagés entre les projets et les langues, et doivent tenir compte des bonnes pratiques en matière de réutilisation et de localisation.
Les arguments sont des paires au format texte nom-valeur. Si vous passez des nombres, assurez-vous de les convertir correctement si nécessaire.
Arguments can be overridden on the {{#chart:}}
invocation by prefixing them with "arg" like arg:name=value
; this allows using different parameters for each chart invocation with the same format, which we expect to be useful for a lot of cases with complex datasets.
<!-- Default Celsius -->
{{#chart:Weekly average temperature chart.chart}}
<!-- Override units to Fahrenheit -->
{{#chart:Weekly average temperature chart.chart|arg:units=F}}
Représentations de la courbe C non transformée par rapport à la courbe F transformée en utilisant le même échantillon de données de température :
Code layout
Vous pouvez nommer vos fonctions comme vous le souhaitez et inclure des fonctions connexes dans le même module ou même utiliser un module pour fournir à la fois des fonctions de modèle et des fonctions de transformation des données. Nous sommes flexibles !
Votre fonction de transformation doit prendre deux arguments : un objet de données tabulaires converti à partir de JSON, et une liste d'arguments provenant de l’invocation qui contiendra des paires clé-valeur. Retourner un objet de données tabulaires modifié (il peut s’agir de l’objet d’entrée après modification, ou d’un nouvel objet dans la même disposition).
local p = {}
local function celsius_to_fahrenheit(val)
return val * 1.8 + 32
end
--
-- input data:
-- * tabular JSON strcuture with 1 label and 2 temp rows stored in C
--
-- arguments:
-- * units: "F" or "C"
--
function p.convert_temps(tab, args)
if args.units == "C" then
-- Stored data is in Celsius
return tab
elseif args.units == "F" then
-- Have to convert if asked for Fahrenheit
for _, row in ipairs(tab.data) do
-- first column is month
row[2] = celsius_to_fahrenheit(row[2])
row[3] = celsius_to_fahrenheit(row[3])
end
return tab
else
error("Units must be either 'C' or 'F'")
end
end
return p
Formatage des données
Voir Aide:Données tabulaires pour la documentation générale sur le format des données tabulaires. La transformation fonctionnera avec une transformation Lua des données, ce qui signifie que les objets et les tableaux basés sur 0 apparaitront comme des tables Lua avec des clés de type chaine de caractères ou des index numériques basés sur 1. Ils seront retransformés en JSON à la sortie pour être traités par le moteur de rendu.
Exemple d’un petit ensemble de données :
{
"license": "CC0-1.0",
"description": {
"en": "Sample monthly temperature data in degrees C"
},
"schema": {
"fields": [
{
"name": "month",
"type": "localized",
"title": { "en": "Month" }
},
{
"name": "low",
"type": "number",
"title": { "en": "Low temp" }
},
{
"name": "high",
"type": "number",
"title": { "en": "High temp" }
}
]
},
"data": [
[ { "en": "January" }, 5, 20 ],
[ { "en": "July" }, 15, 30 ]
]
}
Attention, la validation du format des données sera appliquée après la transformation, de sorte que tout format non valide sera signalé par une erreur si vous passez par le pipeline de transformation proprement dit.
Chaines régionalisées
Les chaines localisables au format { "lang": "string" }
sont préservées dans ce traitement, et si vous renvoyez une chaine multilingue, elle sera localisée au mieux pour le contexte approprié de la sortie au niveau du rendu.
Toutefois, s’il est coûteux d’extraire toutes les chaines possibles, il devrait être acceptable de ne rechercher que la langue d’affichage de la page actuelle et de l’inclure.
Null/nil
Notez que Lua ne permet pas de stocker une valeur nil
dans un tableau ; cela signifie que les tableaux JSON contenant des valeurs null
ne sont pas bien gérés par le filtrage Lua.
Si votre ensemble de données nécessite de travailler avec des cellules de données vides pour lesquelles null
semble approprié dans le JSON, il se peut que nous devions réfléchir à la manière de mieux le prendre en charge.
For instance you can iterate using the tab.schema.fields
list, which always contains every column, and use the array indexes as you got them rather than appending with table.insert
:
proc sum(tab, args)
-- Append a sum field
table.insert(tab.schema.fields, {
["name"] = "sum",
["type"] = "number",
["title"] = {
["en"] = "Sum"
}
})
local sum_index = #tab.schema.fields
for i, row in ipairs(tab.data) do
local sum = 0
-- iterate over schema.fields, not row which
-- may have "holes" in it
for j, field in ipairs(tab.schema.fields) do
if row[j] then
sum = sum + row[j]
end
end
-- Do not use table.insert here!
-- It could go in the wrong column due to adjacent nils.
row[sum_index] = sum
end
end
Chargement d’ensembles de données supplémentaires
Additional Data:
pages may be loaded via mw.ext.data.get()
; note that if you pass the optional language parameter as _
you'll get the full multilingual strings, otherwise it'll pare them down to just the rendering language.
Essayez de ne pas charger trop de données supplémentaires, car cela pourrait augmenter la durée d’exécution et l’utilisation des ressources.
Vous pouvez également charger du code Lua supplémentaire ou des modules de données, qui seront enregistrés pour la gestion de l’invalidation du cache.
Sources de données externes
Tout ce que vous pouvez exécuter à partir d’un module Lua invoqué à partir d’un modèle, vous pouvez l’exécuter ici - cependant, soyez conscient que cela n’inclut pas actuellement les interfaces pour récupérer Wikidata Query Service ou RESTbase, donc les anciennes utilisations de Graph qui nécessitent ces interfaces ne sont pas encore prêtes à être portées.
There is some limited interface for data fetches from Wikidata but this is likely of limited use for charts for now.
De futures API en Lua sont possibles pour d’autres types de recherches, comme dans RESTbase ou via des requêtes SPARQL, et nous espérons être en mesure d’aborder de nombreuses fonctionnalités de ce type à l’avenir par le biais de projets de la liste de souhaits de la communauté.
Performance
Currently the transform and the chart render are run fresh on every page parse, and the resulting output saved into the parser cache. If transforms are found to be unexpectedly expensive we may need to add more aggressive caching and/or resource limits in place.
Assume that speed and memory are constrained and you should aim to conserve them for the best reader and editor experience alike. There are hard limits on memory usage and processing time, which will be enforced similarly as for template Lua code.
Remember: limits for memory and CPU time are the same as for Lua modules used in templates. Using too much memory or running too long will result in the script being canceled and an error message being shown on the page.
Note that input Data: pages are restricted in production to 2 megabytes, but the chart renderer may limit input data size further -- final size limits are to be determined, but if you find youself hitting the limits consider decimating a large data set to fewer data points.
Remember: there's a strict limit on chart input data, as data sets must not only render fast on the server, they are sent to the client for interactive rendering.
For an example if a tabular data set has 24k rows and will be rendered to a chart for mobile and desktop computers, you have many more data points than pixels -- decimating to 1 out of 10 data points either in the input data set or through a transform should reduce processing time. (See the example under #Decimating input data.)
Testing hints
Lua runtime errors should be returned through the pipeline and reported when rendering is attempted. To iterate more quickly you can test your code at the transform or bare Lua level.
Special:ApiSandbox
You can test the actual JSON-transform pipeline with Commons:Special:ApiSandbox pointed at action=jsontransform
, which will produce nicely formatted output from actual input pages.
Debug console
You can wrap a test harness around your module to call it from the Lua editor debugger console during preview, in a pinch:
local p = {}
-- Your fancy transform code here
function p.transform(tab, args)
return tab
end
-- Put p.test() in the debug console while you're editing the code to test
-- with a specific sample data set / args
function p.test(func, args, tabname, lang)
-- pass "_" for lang to get the raw multilingual source data
local tab = mw.ext.data.get(tabname or "Chart Example Data.tab", lang or "_")
local args = args or {
["key"] = "value"
}
tab = p[func or 'transform'](tab, args)
return mw.dumpObject(tab)
end
return p
Real World Examples
Chart transform modules can be found at commons:Category:Chart transform modules.
Chart pages that include transforms can be added to commons:Category:Transformed charts.
Climate example
Cette page est actuellement une ébauche.
|
commons:Data:Climate_Paris.tab has a lot of interesting data in it but unfortunately if we render it as a chart directly the chart itself is not useful:
We can use transforms to focus on certain columns of data and to make conversions such as Celsius to Fahrenheit or mm to inches:
Selecting curves and columns
A simple transform in commons:Module:TabUtils can be used to take the data and using the exported filter function "select
" with argument "cols": "month,averageprecip"
selects the first column (labeled month) of commons:Data:Climate_Paris.tab as xseries data and column 5 (averageprecip
) as an yseries in commons:Data:Climate_Paris/transformed.chart:
"transform": {
"module": "TabUtils",
"function": "select",
"args": {
"cols": "month,averageprecip"
}
},
Calling {{#chart:Climate_Paris/transformed.chart}}
on a wiki page results in:
Other columns can be chosen in the wikicode call by overriding the args of a .chart page that includes a TabUtils transform. Here, the two temperature columns recordhigh and meandaily are chosen as yseries. Note that the yaxis title can not be changed this way, so in this case, the yaxis title is wrong:
{{#chart:Climate Paris/transformed.chart |arg:cols=month,recordhigh,meandaily }}
This override results in the following chart:
If the .chart page default should show all curves, but allow selection of curves in the wikicode as in the above example, it is sufficient if the .chart json code includes the following:
"transform": {
"module": "TabUtils",
"function": "select"
}
Decimating input points
The select
transform in Commons:Module:TabUtils can also decimate the input data set if you have more points than you need to produce a graph (or more than can be fed into the chart renderer successfully!)
Here's a sample that uses a 10x decimation with the select
transform to make a too-large data set render:
"transform": {
"module": "TabUtils",
"function": "select",
"args": {
"decimate": "10"
}
},