gsl-shell.git - gsl-shell

index : gsl-shell.git
gsl-shell
summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat
-rw-r--r--agg-plot/lua-plot.cpp 45
-rw-r--r--demos/nlinfit.lua 3
-rw-r--r--demos/plot.lua 26
-rw-r--r--doc/user-manual/graphics.rst 19
-rw-r--r--graph-init.lua 70
5 files changed, 112 insertions, 51 deletions
diff --git a/agg-plot/lua-plot.cpp b/agg-plot/lua-plot.cpp
index 8a6f186a..834b7c41 100644
--- a/agg-plot/lua-plot.cpp
+++ b/agg-plot/lua-plot.cpp
@@ -142,13 +142,25 @@ static const struct luaL_Reg plot_properties_set[] = {
__END_DECLS
+static void
+configure_plot_env(lua_State* L, int index)
+{
+ INDEX_SET_ABS(L, index);
+ lua_newtable(L); /* create a new table for the environment */
+
+ lua_pushstring(L, "__legend");
+ lua_newtable(L);
+ lua_rawset(L, -3); /* set the field __legend to a new table in the env */
+
+ lua_setfenv (L, index);
+}
+
int
plot_new (lua_State *L)
{
sg_plot *p = push_new_object<sg_plot_auto>(L, GS_PLOT);
- lua_newtable (L);
- lua_setfenv (L, -2);
+ configure_plot_env(L, -1);
if (lua_isstring (L, 1))
{
@@ -165,8 +177,7 @@ canvas_new (lua_State *L)
{
sg_plot *p = push_new_object<sg_plot>(L, GS_PLOT);
- lua_newtable (L);
- lua_setfenv (L, -2);
+ configure_plot_env(L, -1);
p->sync_mode(false);
@@ -694,6 +705,18 @@ char_to_placement_enum(lua_State* L, const char *s)
return pos;
}
+static void set_legend_ref(lua_State* L, sg_plot::placement_e pos,
+ int plot_index, int legend_index)
+{
+ INDEX_SET_ABS_2(L, plot_index, legend_index);
+ lua_getfenv(L, plot_index); /* env = getfenv(plot) */
+ lua_pushstring(L, "__legend");
+ lua_rawget(L, -2); /* leg_table = env.__legend */
+ lua_pushvalue(L, legend_index);
+ lua_rawseti(L, -2, pos); /* leg_table[pos] = legend */
+ lua_pop(L, 1); /* pop environment table */
+}
+
int
plot_set_legend(lua_State *L)
{
@@ -702,10 +725,7 @@ plot_set_legend(lua_State *L)
const char* placement = luaL_optstring(L, 3, "r");
sg_plot::placement_e pos = char_to_placement_enum(L, placement);
- int ref_index = (1 << 16) + (int)pos;
- lua_getfenv(L, 1);
- lua_pushvalue(L, 2);
- lua_rawseti(L, -2, ref_index);
+ set_legend_ref(L, pos, 1, 2);
AGG_LOCK();
p->add_legend(mp, pos);
@@ -722,9 +742,12 @@ plot_get_legend(lua_State *L)
object_check<sg_plot>(L, 1, GS_PLOT);
const char* placement = luaL_optstring(L, 2, "r");
sg_plot::placement_e pos = char_to_placement_enum(L, placement);
- int ref_index = (1 << 16) + (int)pos;
- lua_getfenv(L, 1);
- lua_rawgeti(L, -1, ref_index);
+
+ lua_getfenv(L, 1); /* env = getfenv(plot) */
+ lua_pushstring(L, "__legend");
+ lua_rawget(L, -2); /* leg_table = env.__legend */
+ lua_rawgeti(L, -1, pos); /* push leg_table[pos] */
+
return 1;
}
diff --git a/demos/nlinfit.lua b/demos/nlinfit.lua
index fc6fcb30..dd86d4b0 100644
--- a/demos/nlinfit.lua
+++ b/demos/nlinfit.lua
@@ -83,6 +83,7 @@ local function demo2()
local pl = graph.plot('Non-linear fit / A * exp(a t) sin(w t)')
pl:addline(graph.xyline(x, y), 'blue', {{'marker', size= 5, mark="triangle"}})
+ pl:legend('data', 'blue', 'triangle', {{'stroke'}})
local s = num.nlinfit {n= n, p= #p0}
@@ -90,6 +91,7 @@ local function demo2()
print(s.x, s.chisq)
pl:addline(graph.fxline(|x| fmodel(s.x, x), 0, xs(n)), 'red', {{'dash', 7, 3, 3, 3}})
+ pl:legend('seed', 'red', 'line', {{'stroke'},{'dash',7,3}})
for i=1, 10 do
s:iterate()
@@ -98,6 +100,7 @@ local function demo2()
end
pl:addline(graph.fxline(|x| fmodel(s.x, x), 0, xs(n)), 'red')
+ pl:legend('best fit', 'red', 'line')
pl.pad = true
pl:show()
diff --git a/demos/plot.lua b/demos/plot.lua
index aa5273dd..6b53453d 100644
--- a/demos/plot.lua
+++ b/demos/plot.lua
@@ -114,34 +114,28 @@ local function demo_plot()
end
local function barplot_demo()
- local t = {{'ode', 14, 17, 8}, {'integ', 21, 19, 7}, {'nlfit', 8,12,6}}
+ local t = {{'ode', 14, 17, 8}, {'integ', 21, 19, 7}, {'nlfit', 8,12,6}, legend={'Case A', 'Case B', 'Case C'}}
local p = barplot(t)
p.xtitle = 'Test'
p.ytitle = 'Execution time, ms'
p.title = 'Benchmark results'
+ p:save_svg('barplot.svg', 600, 400)
return p
end
local function legend_demo()
- local p = graph.legend {
- {'sinus', 'red', 'line'},
- {'cosinus', 'blue', 'line', {{'dash', 7, 3}}},
- }
- p:show()
-
- local pi = math.pi
local NS = 64
- local mp = graph.fxplot(math.sin, 0, 2*pi, 'red', 32)
- mp:addline(graph.fxline(math.cos, 0, 2*pi, 32), 'blue', {{'dash', 7,3}})
- mp.title = 'Plot example'
- mp.xtitle = 'x axis title'
+ local p = graph.fxplot(sin, 0, 2*pi, 'red', 32)
+ p:legend('sin', 'red', 'line')
+ p:addline(graph.fxline(cos, 0, 2*pi, 32), 'blue', {{'dash', 7,3}})
+ p:legend('cos', 'blue', 'line', {{'stroke'},{'dash',7,3}})
+ p.title = 'Plot example'
+ p.xtitle = 'x axis title'
- mp:set_legend(p)
- mp:save_svg('demo.svg', 600, 400)
- p:save_svg('legend.svg', 400, 200)
+ p:save_svg('demo.svg', 600, 400)
- echo('Plot saved in "demo.svg" and "legend.svg".')
+ echo('Plot saved in "demo.svg".')
end
return {'Plotting', {
diff --git a/doc/user-manual/graphics.rst b/doc/user-manual/graphics.rst
index 6b4c9e22..86a6a7f4 100644
--- a/doc/user-manual/graphics.rst
+++ b/doc/user-manual/graphics.rst
@@ -551,6 +551,25 @@ You can add elements to a plot in any moments even when it is already shown. GSL
Return the plot legend stored in the given ``placement``.
The placement parameter is interpreted as in the :meth:`~Plot.set_legend` method.
+ .. method:: legend(text, color, symbol[, trans])
+
+ Add to the plot a new legend item with the given ``text``.
+ The symbol used is determinated by the string ``symbol``.
+ Possible values are 'line', 'square' or anything accepted by :func:`graph.marker`.
+ The optional ``trans`` parameter should be a :ref:`graphical transform <graphics-transforms>`.
+ If omitted the appropriate default is chosen based on the symbol type.
+
+ Example::
+
+ use 'math'
+
+ p = graph.plot('plot example')
+ p:addline(graph.fxline(sin, 0, 2*pi), 'red')
+ p:legend('sinus', 'red', 'line')
+ p:addline(graph.fxline(cos, 0, 2*pi), 'blue', {{'dash',7,3}})
+ p:legend('cosinus', 'blue', 'line', {{'stroke'},{'dash',7,3}})
+ p:show()
+
.. method:: set_categories(axis, categories)
Configure the given ``axis`` (a letter, 'x' or 'y') to use a custom set of labels specified by ``categories``.
diff --git a/graph-init.lua b/graph-init.lua
index 4cc311e8..8e9076b9 100644
--- a/graph-init.lua
+++ b/graph-init.lua
@@ -118,6 +118,7 @@ end
function graph.barplot(t)
local nr, nc = #t, #t[1] - 1
+ local legend_text = t.legend
local pad = 0.1
local dx = (1-2*pad)/nc
local cat = {}
@@ -135,6 +136,13 @@ function graph.barplot(t)
p:add(rect, graph.webcolor(j))
p:add(rect, 'black', {{'stroke', width= 0.5}})
end
+
+ end
+
+ if legend_text then
+ for j = 1, nc do
+ p:legend(legend_text[j], graph.webcolor(j), 'square')
+ end
end
p:set_categories('x', cat)
@@ -283,34 +291,48 @@ end
local function legend_symbol(sym, dx, dy)
if sym == 'square' then
return graph.rect(5+dx, 5+dy, 15+dx, 15+dy)
- elseif sym == 'circle' then
- return graph.ellipse(10+dx, 10+dy, 5, 5)
elseif sym == 'line' then
- return graph.segment(2+dx, 10+dy, 18+dx, 10+dy), {'stroke'}
+ return graph.segment(2+dx, 10+dy, 18+dx, 10+dy), {{'stroke'}}
else
- error('invalid legend symbol: ' .. sym)
+ return graph.marker(10+dx, 10+dy, sym, 8)
end
end
-function graph.legend(entries)
- local n = #entries
- local p = graph.plot()
- p.units, p.clip = false, false
- for k= 1, n do
- local text, color, symspec, trans = unpack(entries[k])
- local y = (k-1) * 20
- local sym, symtr = legend_symbol(symspec, 0, y)
- local tr
- if symtr then
- tr = { symtr }
- if trans then
- for j, xtr in ipairs(trans) do tr[#tr+1] = xtr end
- end
- else
- tr = trans
- end
- p:add(sym, color, tr)
- p:add(graph.textshape(25, y + 6, text, 14), 'black')
+local function plot_legend(self, text, color, symspec, trans)
+ local lg = self:get_legend()
+ local env = debug.getfenv(self)
+
+ if not lg then
+ lg = graph.plot()
+ lg.units = false
+ self:set_legend(lg)
end
- return p
+
+ local k = env.__lg_count or 0
+ local y = -k * 20
+
+ local sym, symtr = legend_symbol(symspec, 0, y)
+
+ local tr = (trans and trans or symtr)
+
+ lg:add(sym, color, tr)
+ lg:add(graph.textshape(25, y + 6, text, 14), 'black')
+
+ env.__lg_count = k+1
+ self:update()
+end
+
+local function redirect_plot()
+ local reg = debug.getregistry()
+ local mt = reg['GSL.plot']
+ local plot_index = mt.__index
+
+ local function index_redirect(t, k)
+ if k == 'legend' then return plot_legend end
+ return plot_index(t, k)
+ end
+
+ mt.__index = index_redirect
end
+
+redirect_plot()
generated by cgit v1.2.3 (git 2.39.1) at 2025年09月16日 15:08:15 +0000

AltStyle によって変換されたページ (->オリジナル) /