How can I delete a line between time gap in Line chart (Bokeh)?

时间:2019-04-17 01:56:57

标签: python pandas bokeh

I have been trying to create a line chart that represents 'values' as y axis and 'time' as x axis. I have successfully done so.

However, when there's a large time gap between values, there exist lines connected two dots from those values which create an ugly looking scenario.

Therefore, I would like to get rid of those lines.

Here's my runnable code:

# Import Library
import random
import pandas as pd
from bokeh.core.properties import value
from bokeh.io import show, output_notebook, export_png
from bokeh.plotting import figure, output_file
from bokeh.models import ColumnDataSource, Legend, HoverTool, layouts, CustomJS, Select, Circle, RangeTool
from bokeh.layouts import column
output_notebook() # Render inline in a Jupyter Notebook


# Create Line Chart
def create_line_chart_bokeh():

    # Set data
    dates = ['24-11-2017', '28-11-2017', '29-11-2017',
            '23-03-2018', '27-03-2018', '12-08-2018']
    dates = list(map(lambda i: pd.Timestamp(i), dates))
    values = [random.randrange(101) for _ in range(len(dates))]
    source = ColumnDataSource(data=dict(date=dates, close=values))

    # Set Hover
    TOOLTIPS = [
    ("Average Score", "@close")
    ]

    # Set plot
    p = figure(plot_height=300, plot_width=800, tools="xpan", toolbar_location=None,
               tooltips=TOOLTIPS, x_axis_type="datetime", x_axis_location="above",
               background_fill_color="white", x_range=(dates[0], dates[int(len(dates)-1)]), title='Test Line Chart')

    # Set Line and Circle colours
    line_colour = '#59819a'
    circle_colour = '#ef5b45'

    p.line('date', 'close', source=source, color=line_colour)
    p.circle('date', 'close', source=source, color=circle_colour, size=4)
    p.yaxis.axis_label = 'Scores' # set y axis label

    # Set Time Selection Box
    select = figure(title="Drag the middle and edges of the selection box to change the range above",
                    plot_height=130, plot_width=800, y_range=p.y_range,
                    x_axis_type="datetime", y_axis_type=None,
                    tools="", toolbar_location=None, background_fill_color="#efefef")

    range_tool = RangeTool(x_range=p.x_range)
    range_tool.overlay.fill_color = 'navy'
    range_tool.overlay.fill_alpha = 0.2

    select.line('date', 'close', source=source, color=line_colour)
    select.ygrid.grid_line_color = None
    select.add_tools(range_tool)
    select.toolbar.active_multi = range_tool

    # Show the result
    show(column(p, select))

    return None


# Call Function
create_line_chart_bokeh()

LineChart

As can be seen above, those circled areas are not wanted. Is there anyone who has experiences or ideas to solve this problem?

This is a draft for what I want to achieve. I am thinking a time gap for deleting lines can be adjustable, or fixed as 2-or-3 month gap.

Example

Thank you in advance,

Update!!

According to the answer below, the line now looks proper. However, there'a slight problem on hovering line itself. Hovering on circles work perfectly fine.

# Import Library
import random
import pandas as pd
from bokeh.core.properties import value
from bokeh.io import show, export_png, output_notebook
from bokeh.plotting import figure, output_file
from bokeh.models import ColumnDataSource, Legend, HoverTool, layouts, CustomJS, Select, Circle, RangeTool
from bokeh.layouts import column
from datetime import date
output_notebook() # Render inline in a Jupyter Notebook


# Create Line Chart
def create_line_chart_bokeh():

    # Set data
    dates = ['24-11-2017', '28-11-2017', '29-11-2017',
            '23-03-2018', '27-03-2018', '12-08-2018']
    dates = list(map(lambda i: pd.Timestamp(i), dates))
    values = [random.randrange(101) for _ in range(len(dates))]
    source = ColumnDataSource(data=dict(date=dates, close=values))

    # Set Hover
    TOOLTIPS = [
    ("Average Score", "@close")
    ]

    # Set plot
    p = figure(plot_height=300, plot_width=800, tools="xpan", toolbar_location=None,
               tooltips=TOOLTIPS, x_axis_type="datetime", x_axis_location="above",
               background_fill_color="white", x_range=(dates[0], dates[int(len(dates)-1)]), title='Test Line Chart')

    # Set Line and Circle colours
    line_colour = '#59819a'
    circle_colour = '#ef5b45'
    for i in range(len(dates)):
        try:
            diff = dates[i+1] - dates[i] #Compute difference between dates in days
            if diff.days < 30:
                p.line([dates[i], dates[i+1]], [values[i], values[i+1]], color=line_colour) #Only plot a line if difference in days < 30
        except IndexError:
            pass

    p.circle('date', 'close', source=source, color=circle_colour, size=4)
    p.yaxis.axis_label = 'Scores' # set y axis label

    # Set Time Selection Box
    select = figure(title="Drag the middle and edges of the selection box to change the range above",
                    plot_height=130, plot_width=800, y_range=p.y_range,
                    x_axis_type="datetime", y_axis_type=None,
                    tools="", toolbar_location=None, background_fill_color="#efefef")

    range_tool = RangeTool(x_range=p.x_range)
    range_tool.overlay.fill_color = 'navy'
    range_tool.overlay.fill_alpha = 0.2

    for i in range(len(dates)):
        try:
            diff = dates[i+1] - dates[i] #Compute difference between dates in days
            if diff.days < 30:
                select.line([dates[i], dates[i+1]], [values[i], values[i+1]], color=line_colour) #Only plot a line if difference in days < 30
        except IndexError:
            pass
    select.ygrid.grid_line_color = None
    select.add_tools(range_tool)
    select.toolbar.active_multi = range_tool

    # Show the result
    show(column(p, select))

    return None


# Call Function
create_line_chart_bokeh()

Hovering on Circles

Circle

Hovering on the Line

Line

Solved!!

Based on the code below, I am now able to accomplish all the requirements. I took some pieces of the code and modified it further for my project.

# Import Library
import random
import pandas as pd
from bokeh.core.properties import value
from bokeh.io import show, export_png, output_notebook
from bokeh.plotting import figure, output_file
from bokeh.models import ColumnDataSource, Legend, HoverTool, layouts, CustomJS, Select, Circle, RangeTool
from bokeh.layouts import column
from datetime import date
output_notebook() # Render inline in a Jupyter Notebook


# Create Line Chart
def create_line_chart_bokeh():

    # Set data
    dates = ['24-11-2017', '28-11-2017', '29-11-2017',
            '23-03-2018', '27-03-2018', '12-08-2018']
    dates = list(map(lambda i: pd.Timestamp(i), dates))
    values = [random.randrange(101) for _ in range(len(dates))]
    source = ColumnDataSource(data=dict(date=dates, close=values))

    # Set plot
    p = figure(plot_height=300, plot_width=800, tools="xpan", toolbar_location="right",
               x_axis_type="datetime", x_axis_location="above",
               background_fill_color="white", x_range=(dates[0], dates[int(len(dates)-1)]), title='Test Line Chart')

    # Set Line and Circle colours
    line_colour = '#59819a'
    circle_colour = '#ef5b45'
    lineSource = {'date': [], 'close': []}
    date, close = [], []
    for i in range(len(dates)):
        try:
            diff = dates[i+1] - dates[i]
            if diff.days < 30:
                date.extend([dates[i], dates[i+1]])
                close.extend([values[i], values[i+1]])
            else:
                lineSource['date'].append(date)
                lineSource['close'].append(close)
                date, close = [], []
        except IndexError:
            pass
    lines = p.multi_line(xs='date', ys='close', source=ColumnDataSource(lineSource), color=line_colour)

    circles = p.circle('date', 'close', source=source, color=circle_colour, size=4)
    p.yaxis.axis_label = 'Scores' # set y axis label

    hoverCircles = HoverTool(renderers=[circles], tooltips=[("Average Score", "@close")])
    p.add_tools(hoverCircles)
    hoverLines = HoverTool(renderers=[lines], tooltips=[("Average Score", "$y")])
    p.add_tools(hoverLines)

    # Set Time Selection Box
    select = figure(title="Drag the middle and edges of the selection box to change the range above",
                    plot_height=130, plot_width=800, y_range=p.y_range,
                    x_axis_type="datetime", y_axis_type=None,
                    tools="", toolbar_location=None, background_fill_color="#efefef")

    range_tool = RangeTool(x_range=p.x_range)
    range_tool.overlay.fill_color = 'navy'
    range_tool.overlay.fill_alpha = 0.2

    select.line('date', 'close', source=source, color=line_colour)
    select.ygrid.grid_line_color = None
    select.add_tools(range_tool)
    select.toolbar.active_multi = range_tool

    # Show the result
    show(column(p, select))

    return None


# Call Function
create_line_chart_bokeh()

1 个答案:

答案 0 :(得分:0)

只需用for循环绘制该行即可。每次检查日期之间的距离是否小于30天,如果是,则绘制线条。

import { HttpClient, HttpHeaders } from '@angular/common/http';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json'
  })
};


this.http.post<any>
      (`Your URL`, formData).subcribe(
      (res) => {
        console.log(res);
      },
      err => console.log(err)
    );

to_utf8

相关问题