diff --git a/docs/en-us/documentation.md b/docs/en-us/documentation.md index 54d1e513..87d11b66 100644 --- a/docs/en-us/documentation.md +++ b/docs/en-us/documentation.md @@ -340,7 +340,7 @@ dataZoom:dataZoom components for zoom-in and zoom-out. With them, it is possib It specifies whether to use the datazoom component. * datazoom_type -> str defalut -> 'slider' - datazoom type, 'slider' or 'inside' + datazoom type, 'slider', 'inside', or 'both' * datazoom_range -> list defalut -> [50, 100] The range percentage of the window out of the data extent, in the range of 0 ~ 100. @@ -1028,6 +1028,12 @@ add(name, x_axis, y_axis, data, **kwargs) data of yAxis, it must be catagory axis. * data -> [[],[]] data array of series, it is represented by a two-dimension array +* is_date_heatmap -> bool + default -> False + Whether it is a date heatmap +* date_range -> str/list + date range of date heatmap, "2016" is year 2016, ["2016-5-5", "2017-5-5"] is 2016/5/5-2017/5/5 + ```python import random from pyecharts import HeatMap @@ -1044,6 +1050,23 @@ heatmap.render() ``` ![heatmap-0](https://github.com/chenjiandongx/pyecharts/blob/master/images/heatmap-0.gif) +```python +import datetime +import random +from pyecharts import HeatMap + +begin = datetime.date(2017, 1, 1) +end = datetime.date(2017, 12, 31) +data = [[str(begin + datetime.timedelta(days=i)), + random.randint(0, 100)] for i in range((end - begin).days+1)] +heatmap = HeatMap("日历热力图示例") +heatmap.add("日历热力图", data, date_range=["2017"], is_visualmap=True, + is_legend_show=False, is_date_heatmap=True, visual_orient="horizontal", + visual_pos="center", visual_top="top") +heatmap.render() +``` +![heatmap-0](https://github.com/chenjiandongx/pyecharts/blob/master/images/heatmap-1.gif) + **Tip:** Thermodynamic chart have to cooperate with VisualMap in use. diff --git a/docs/zh-cn/documentation.md b/docs/zh-cn/documentation.md index b7b3897d..a25443b5 100644 --- a/docs/zh-cn/documentation.md +++ b/docs/zh-cn/documentation.md @@ -339,7 +339,7 @@ cast(seq) * is_datazoom_show -> bool 是否使用区域缩放组件,默认为 False * datazoom_type -> str - 区域缩放组件类型,默认为'slider',有'slider', 'inside'可选 + 区域缩放组件类型,默认为'slider',有'slider', 'inside', 'both'可选 * datazoom_range -> list 区域缩放的范围,默认为[50, 100] * datazoom_orient -> str @@ -1203,6 +1203,11 @@ add(name, x_axis, y_axis, data, **kwargs) y 坐标轴数据。需为类目轴,也就是不能是数值。 * data -> [list],包含列表的列表 数据项,数据中,每一行是一个『数据项』,每一列属于一个『维度』 +* is_date_heatmap -> bool + 是否是日历热力图,默认为 False +* date_range -> str/list + 日历热力图的日期, "2016"表示2016年, ["2016-5-5", "2017-5-5"]表示2016年5月5日至2017年5月5日 + ```python import random from pyecharts import HeatMap @@ -1218,6 +1223,23 @@ heatmap.render() ``` ![heatmap-0](https://github.com/chenjiandongx/pyecharts/blob/master/images/heatmap-0.gif) +```python +import datetime +import random +from pyecharts import HeatMap + +begin = datetime.date(2017, 1, 1) +end = datetime.date(2017, 12, 31) +data = [[str(begin + datetime.timedelta(days=i)), + random.randint(0, 100)] for i in range((end - begin).days+1)] +heatmap = HeatMap("日历热力图示例") +heatmap.add("日历热力图", data, date_range=["2017"], is_visualmap=True, + is_legend_show=False, is_date_heatmap=True, visual_orient="horizontal", + visual_pos="center", visual_top="top") +heatmap.render() +``` +![heatmap-0](https://github.com/chenjiandongx/pyecharts/blob/master/images/heatmap-1.gif) + **Note:** 热力图必须配合 [通用配置项](https://github.com/chenjiandongx/pyecharts/blob/master/docs/zh-cn/documentation.md#通用配置项) 中的 VisualMap 使用才有效果。 diff --git a/pyecharts/charts/heatmap.py b/pyecharts/charts/heatmap.py index c883faa6..6a1620cd 100644 --- a/pyecharts/charts/heatmap.py +++ b/pyecharts/charts/heatmap.py @@ -21,7 +21,7 @@ class HeatMap(Base): def add(self, *args, **kwargs): self.__add(*args, **kwargs) - def __add(self, name, x_axis, y_axis, data, **kwargs): + def __add(self, *args, **kwargs): """ :param name: @@ -36,16 +36,14 @@ class HeatMap(Base): :param kwargs: :return: """ + if kwargs.get('is_date_heatmap', None) is True: + name, data = args + else: + name, x_axis, y_axis, data = args + chart = get_all_options(**kwargs) self._option.get('legend')[0].get('data').append(name) - xaxis, yaxis = chart['xy_axis'] - self._option.update(xAxis=xaxis, yAxis=yaxis) - self._option.get('xAxis')[0].update( - type='category', data=x_axis, splitArea={"show": True}) - self._option.get('yAxis')[0].update( - type='category', data=y_axis, splitArea={"show": True}) - self._option.get('series').append({ "type": "heatmap", "name": name, @@ -53,4 +51,18 @@ class HeatMap(Base): "label": chart['label'], "seriesId": self._option.get('series_id'), }) + + if kwargs.get('is_date_heatmap', None) is True: + self._option.get('toolbox')['show'] = False + self._option.get('series')[0].update(coordinateSystem='calendar', + calendarIndex=0) + self._option.update(calendar=chart['calendar']) + else: + xaxis, yaxis = chart['xy_axis'] + self._option.update(xAxis=xaxis, yAxis=yaxis) + self._option.get('xAxis')[0].update( + type='category', data=x_axis, splitArea={"show": True}) + self._option.get('yAxis')[0].update( + type='category', data=y_axis, splitArea={"show": True}) + self._config_components(**kwargs) diff --git a/pyecharts/option.py b/pyecharts/option.py index 52ccd4dd..b6a7f66f 100644 --- a/pyecharts/option.py +++ b/pyecharts/option.py @@ -795,7 +795,7 @@ def datazoom(is_datazoom_show=False, :param is_datazoom_show: It specifies whether to use the datazoom component. :param datazoom_type: - datazoom type, 'slider' or 'inside' + datazoom type, 'slider', 'inside', or 'both' :param datazoom_range: The range percentage of the window out of the data extent,in the range of 0 ~ 100. @@ -816,18 +816,24 @@ def datazoom(is_datazoom_show=False, if datazoom_range: if len(datazoom_range) == 2: _min, _max = datazoom_range - if datazoom_type not in ("slider", "inside"): + if datazoom_type not in ("slider", "inside", "both"): datazoom_type = "slider" - _datazoom = { + _datazoom = [] + _datazoom_config = { "show": is_datazoom_show, - "type": datazoom_type, + "type": "slider", "start": _min, "end": _max, "orient": datazoom_orient, "xAxisIndex": datazoom_xaxis_index, "yAxisIndex": datazoom_yaxis_index } - return [_datazoom] + if datazoom_type == "both": + _datazoom.append(_datazoom_config.copy()) + datazoom_type = 'inside' + _datazoom_config['type'] = datazoom_type + _datazoom.append(_datazoom_config) + return _datazoom @collectfuncs @@ -1127,6 +1133,16 @@ def tooltip(type=None, return _tooltip +@collectfuncs +def calendar(date_range=None, + cellSize=['auto', 20], **kwargs): + _calendar = { + "range": date_range, + "cellSize": cellSize + } + return _calendar + + def get_all_options(**kwargs): """ Return all component options of charts diff --git a/test/test_bar.py b/test/test_bar.py index f12ceb4d..a76509c3 100644 --- a/test/test_bar.py +++ b/test/test_bar.py @@ -53,51 +53,52 @@ def test_bar(): bar.render() -def test_bar_datazoom_slider(): - attr = ["{}月".format(i) for i in range(1, 13)] - v1 = [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, - 135.6, 162.2, 32.6, 20.0, 6.4, 3.3] - v2 = [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, - 175.6, 182.2, 48.7, 18.8, 6.0, 2.3] - bar = Bar("柱状图示例") - bar.add("蒸发量", attr, v1, mark_line=["average"], - mark_point=["max", "min"]) - bar.add("降水量", attr, v2, mark_line=["average"], - mark_point=["max", "min"], is_datazoom_show=True, - datazoom_range=[50, 80]) - assert "dataZoom" in bar._repr_html_() - bar.render() - +def test_bar_datazoom_undefined(): + # bar dataZoom undefined-type attr = ["{}天".format(i) for i in range(30)] v1 = [random.randint(1, 30) for _ in range(30)] - bar = Bar("Bar - datazoom - slider 示例") + bar = Bar("Bar - datazoom 默认 示例") bar.add("", attr, v1, is_label_show=True, is_datazoom_show=True) - assert ': "slider"' in bar._repr_html_() - assert ': "inside"' not in bar._repr_html_() - bar.render() + html_content = bar._repr_html_() + assert "dataZoom" in html_content + assert ': "slider"' in html_content + assert ': "inside"' not in html_content + + +def test_bar_datazoom_slider(): + # bar dataZoom slider-type + attr = ["{}天".format(i) for i in range(30)] + v1 = [random.randint(1, 30) for _ in range(30)] + bar = Bar("Bar - datazoom 默认 示例") + bar.add("", attr, v1, is_datazoom_show=True, datazoom_type='slider', + datazoom_range=[10, 25]) + html_content = bar._repr_html_() + assert "dataZoom" in html_content + assert ': "slider"' in html_content + assert ': "inside"' not in html_content def test_bar_datazoom_inside(): # bar dataZoom inside-type - attr = ["{}月".format(i) for i in range(1, 13)] - v1 = [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, - 135.6, 162.2, 32.6, 20.0, 6.4, 3.3] - v2 = [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, - 175.6, 182.2, 48.7, 18.8, 6.0, 2.3] - bar = Bar("柱状图示例") - bar.add("蒸发量", attr, v1, mark_line=["average"], - mark_point=["max", "min"]) - bar.add("降水量", attr, v2, mark_line=["average"], - mark_point=["max", "min"], is_datazoom_show=True, - datazoom_range=[20, 60], datazoom_type='inside') - assert "dataZoom" in bar._repr_html_() - bar.render() - attr = ["{}天".format(i) for i in range(30)] v1 = [random.randint(1, 30) for _ in range(30)] bar = Bar("Bar - datazoom - inside 示例") bar.add("", attr, v1, is_datazoom_show=True, datazoom_type='inside', - datazoom_range=[10, 25], is_xaxis_show=False, is_yaxis_show=False) - assert ': "inside"' in bar._repr_html_() - assert ': "slider"' not in bar._repr_html_() - bar.render() + datazoom_range=[10, 25]) + html_content = bar._repr_html_() + assert "dataZoom" in html_content + assert ': "inside"' in html_content + assert ': "slider"' not in html_content + + +def test_bar_datazoom_both(): + # bar dataZoom both-type + attr = ["{}天".format(i) for i in range(30)] + v1 = [random.randint(1, 30) for _ in range(30)] + bar = Bar("Bar - datazoom - both 示例") + bar.add("", attr, v1, is_datazoom_show=True, datazoom_type='both', + datazoom_range=[10, 25]) + html_content = bar._repr_html_() + assert "dataZoom" in html_content + assert ': "inside"' in html_content + assert ': "slider"' in html_content diff --git a/test/test_heatmap.py b/test/test_heatmap.py index 7234846c..869db2f3 100644 --- a/test/test_heatmap.py +++ b/test/test_heatmap.py @@ -15,3 +15,19 @@ def test_heatmap(): xaxis_name='XNAME', yaxis_name='YNAME', yaxis_name_pos='end', yaxis_name_gap=5) heatmap.render() + + +def test_heatmap_date(): + import random + import datetime + begin = datetime.date(2017, 1, 1) + end = datetime.date(2017, 12, 31) + data = [[str(begin + datetime.timedelta(days=i)), + random.randint(0, 100)] for i in range((end - begin).days + 1)] + heatmap = HeatMap("日历热力图示例") + heatmap.add("日历热力图", data, + is_visualmap=True, is_legend_show=False, + is_date_heatmap=True, date_range="2017", + visual_orient="horizontal", visual_pos="center", + visual_top="top") + heatmap.render()