Skip to content

Commit 5c240d9

Browse files
authored
Merge pull request bqplot#190 from ssunkara1/bug_fixes
Tooltip positioning bug fix. Pyplot hline and vline.
2 parents 82af6da + ed00699 commit 5c240d9

File tree

5 files changed

+150
-17
lines changed

5 files changed

+150
-17
lines changed

bqplot/figure.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,10 @@ class Figure(DOMWidget):
122122
animation_duration = Int().tag(sync=True, display_name='Animation duration')
123123

124124
def _scale_x_default(self):
125-
return LinearScale(min=0, max=1)
125+
return LinearScale(min=0, max=1, allow_padding=False)
126126

127127
def _scale_y_default(self):
128-
return LinearScale(min=0, max=1)
128+
return LinearScale(min=0, max=1, allow_padding=False)
129129

130130
def save_png(self):
131131
self.send({"type": "save_png"})

bqplot/pyplot.py

+79-4
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,71 @@ def axes(mark=None, options={}, **kwargs):
346346
return axes
347347

348348

349+
def grids(fig=None, value='solid'):
350+
"""Sets the value of the grid_lines for the axis to the passed value.
351+
The default value is `solid`.
352+
353+
Parameters
354+
----------
355+
fig: Figure or None(default: None)
356+
The figure for which the axes should be edited. If the value is None,
357+
the current figure is used.
358+
value: {'none', 'solid', 'dashed'}
359+
The display of the grid_lines
360+
"""
361+
362+
if fig is None:
363+
fig = current_figure()
364+
for a in fig.axes:
365+
a.grid_lines = value
366+
367+
368+
def hline(level, fig=None, preserve_domain=False, **kwargs):
369+
"""Draws a horizontal line at the given level.
370+
371+
Parameters
372+
----------
373+
level: float
374+
The level at which to draw the horizontal line.
375+
fig: Figure or None
376+
The figure to which the horizontal line is to be added.
377+
If the value is None, the current figure is used.
378+
preserve_domain: boolean (default: False)
379+
If true, the line does not affect the domain of the 'y' scale.
380+
"""
381+
default_colors = kwargs.pop('colors', ['dodgerblue'])
382+
default_width = kwargs.pop('stroke_width', 1)
383+
if fig is None:
384+
fig = current_figure()
385+
sc_x = fig.scale_x
386+
plot([0., 1.], [level, level], scales={'x': sc_x}, preserve_domain={'x': True,
387+
'y': preserve_domain}, axes=False, colors=default_colors,
388+
stroke_width=default_width, update_context=False)
389+
390+
391+
def vline(level, fig=None, preserve_domain=False, **kwargs):
392+
"""Draws a vertical line at the given level.
393+
394+
Parameters
395+
----------
396+
level: float
397+
The level at which to draw the vertical line.
398+
fig: Figure or None
399+
The figure to which the vertical line is to be added.
400+
If the value is None, the current figure is used.
401+
preserve_domain: boolean (default: False)
402+
If true, the line does not affect the domain of the 'x' scale.
403+
"""
404+
default_colors = kwargs.pop('colors', ['dodgerblue'])
405+
default_width = kwargs.pop('stroke_width', 1)
406+
if fig is None:
407+
fig = current_figure()
408+
sc_y = fig.scale_y
409+
plot([level, level], [0., 1.], scales={'y': sc_y}, preserve_domain={'x': preserve_domain,
410+
'y': True}, axes=False, colors=default_colors,
411+
stroke_width=default_width, update_context=False)
412+
413+
349414
def _draw_mark(mark_type, options={}, axes_options={}, **kwargs):
350415
"""Draw the mark of specified mark type.
351416
@@ -364,6 +429,7 @@ def _draw_mark(mark_type, options={}, axes_options={}, **kwargs):
364429
"""
365430
fig = kwargs.pop('figure', current_figure())
366431
scales = kwargs.pop('scales', {})
432+
update_context = kwargs.pop('update_context', True)
367433

368434
# Going through the list of data attributes
369435
for name in mark_type.class_trait_names(scaled=True):
@@ -375,7 +441,8 @@ def _draw_mark(mark_type, options={}, axes_options={}, **kwargs):
375441
# create a scale for this.
376442
continue
377443
elif name in scales:
378-
_context['scales'][dimension] = scales[name]
444+
if update_context:
445+
_context['scales'][dimension] = scales[name]
379446
# Scale has to be fetched from the conext or created as it has not
380447
# been passed.
381448
elif dimension not in _context['scales']:
@@ -394,7 +461,8 @@ def _draw_mark(mark_type, options={}, axes_options={}, **kwargs):
394461
# scale type.
395462
scales[name] = compat_scale_types[0](**options.get(name, {}))
396463
# Adding the scale to the conext scales
397-
_context['scales'][dimension] = scales[name]
464+
if update_context:
465+
_context['scales'][dimension] = scales[name]
398466
else:
399467
scales[name] = _context['scales'][dimension]
400468

@@ -850,8 +918,15 @@ def current_figure():
850918

851919

852920
def get_context():
853-
"""Used for debug only. Return the current global context dictionary."""
854-
return _context
921+
"""Used for debug only. Return a copy of the current global context dictionary."""
922+
return {k: v for k, v in _context.items()}
923+
924+
925+
def set_context(context):
926+
"""Sets the current global context dictionary. All the attributes to be set
927+
should be set. Otherwise, it will result in unpredictable behavior."""
928+
global _context
929+
_context = {k: v for k, v in context.items()}
855930

856931

857932
def _fetch_axis(fig, dimension, scale):

examples/Basic Plotting/Pyplot.ipynb

+57-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,39 @@
9090
"plt.show()"
9191
]
9292
},
93+
{
94+
"cell_type": "markdown",
95+
"metadata": {},
96+
"source": [
97+
"### Horizontal and Vertical Lines"
98+
]
99+
},
100+
{
101+
"cell_type": "code",
102+
"execution_count": null,
103+
"metadata": {
104+
"collapsed": false
105+
},
106+
"outputs": [],
107+
"source": [
108+
"## adding a horizontal line at y=0\n",
109+
"plt.hline(0)\n",
110+
"plt.show()"
111+
]
112+
},
113+
{
114+
"cell_type": "code",
115+
"execution_count": null,
116+
"metadata": {
117+
"collapsed": true
118+
},
119+
"outputs": [],
120+
"source": [
121+
"## adding a vertical line at x=4 with stroke_width and colors being passed.\n",
122+
"plt.vline(4., stroke_width=2, colors=['orangered'])\n",
123+
"plt.show()"
124+
]
125+
},
93126
{
94127
"cell_type": "markdown",
95128
"metadata": {},
@@ -255,6 +288,25 @@
255288
"plt.show()"
256289
]
257290
},
291+
{
292+
"cell_type": "markdown",
293+
"metadata": {},
294+
"source": [
295+
"### Adding grid lines"
296+
]
297+
},
298+
{
299+
"cell_type": "code",
300+
"execution_count": null,
301+
"metadata": {
302+
"collapsed": true
303+
},
304+
"outputs": [],
305+
"source": [
306+
"plt.grids()\n",
307+
"plt.show()"
308+
]
309+
},
258310
{
259311
"cell_type": "markdown",
260312
"metadata": {},
@@ -346,7 +398,7 @@
346398
"\n",
347399
"## preserving the x scale and changing the y scale\n",
348400
"plt.scales(scales={'x': plt.Keep})\n",
349-
"plt.plot(x, y_data_2, colors=['lightgreen'], axes_options={'y': {'side': 'right', 'color': 'lightgreen'}})\n",
401+
"plt.plot(x, y_data_2, colors=['orange'], axes_options={'y': {'side': 'right', 'color': 'orange'}})\n",
350402
"plt.show()"
351403
]
352404
},
@@ -623,6 +675,10 @@
623675
"nbconvert_exporter": "python",
624676
"pygments_lexer": "ipython2",
625677
"version": "2.7.11"
678+
},
679+
"widgets": {
680+
"state": {},
681+
"version": "1.0.0"
626682
}
627683
},
628684
"nbformat": 4,

js/src/Mark.js

+8-7
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ define(["jupyter-js-widgets", "d3", "underscore"],
247247
var ref_el = d3.select(document.body).select("#notebook").node();
248248
var ref_mouse_pos = d3.mouse(ref_el);
249249

250-
var mouse_pos = d3.mouse(this.parent.el);
250+
var parent_node = this.parent.el.parentElement;
251+
var mouse_pos = d3.mouse(parent_node);
251252
if(mouse_events === undefined || mouse_events === null ||
252253
(!(mouse_events))) {
253254
this.tooltip_div.style("pointer-events", "none");
@@ -263,14 +264,14 @@ define(["jupyter-js-widgets", "d3", "underscore"],
263264
//node
264265
var parent_rect = this.parent.el.getBoundingClientRect();
265266
var tooltip_div_rect = this.tooltip_div.node().getBoundingClientRect();
266-
this.tooltip_div.style("left", (this.parent.el.offsetLeft + 5 + parent_rect.width * 0.5 -
267-
tooltip_div_rect.width * 0.5) + "px")
268-
.style("top", (this.parent.el.offsetTop + 5 + parent_rect.height * 0.5 -
269-
tooltip_div_rect.height * 0.5) + "px");
267+
this.tooltip_div.style("left", (parent_node.offsetLeft + 5 + parent_rect.width * 0.5 -
268+
tooltip_div_rect.width * 0.5 - ref_el.scrollLeft) + "px")
269+
.style("top", (parent_node.offsetTop + 5 + parent_rect.height * 0.5 -
270+
tooltip_div_rect.height * 0.5 - ref_el.scrollTop) + "px");
270271
}
271272
else {
272-
this.tooltip_div.style("left", (mouse_pos[0] + this.parent.el.offsetLeft + 5) + "px")
273-
.style("top", (mouse_pos[1] + this.parent.el.offsetTop + 5) + "px");
273+
this.tooltip_div.style("left", (mouse_pos[0] + parent_node.offsetLeft - ref_el.scrollLeft + 5) + "px")
274+
.style("top", (mouse_pos[1] + parent_node.offsetTop - ref_el.scrollTop + 5) + "px");
274275
}
275276
}
276277
},

js/src/MarketMap.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -599,16 +599,17 @@ define(["jupyter-js-widgets", "d3", "./Figure", "underscore"],
599599
var ref_el = d3.select(document.body).select("#notebook").node();
600600
var ref_mouse_pos = d3.mouse(ref_el);
601601

602-
var mouse_pos = d3.mouse(this.el);
602+
var parent_node = this.el.parentElement;
603+
var mouse_pos = d3.mouse(parent_node);
603604
var that = this;
604605
var tooltip_div = this.tooltip_div;
605606
tooltip_div.transition()
606607
.style("opacity", 0.9)
607608
.style("display", null);
608609

609610
// the +5s are for breathing room for the tool tip
610-
tooltip_div.style("left", (mouse_pos[0] + this.el.offsetLeft + 5) + "px")
611-
.style("top", (mouse_pos[1] + this.el.offsetTop + 5) + "px");
611+
tooltip_div.style("left", (mouse_pos[0] + parent_node.offsetLeft - ref_el.scrollLeft + 5) + "px")
612+
.style("top", (mouse_pos[1] + parent_node.offsetTop - ref_el.scrollTop + 5) + "px");
612613

613614
tooltip_div.select("table").remove();
614615
if(! this.tooltip_view) {

0 commit comments

Comments
 (0)