简体   繁体   中英

How to Bokeh plot a combination of Miles and Metres on axis (e.g. 7.5 Miles 100m, 7.5 Miles 200m, 8 Miles 100m…)

I need to plot some data with Bokeh which has distance as the x-axis. However the distance data I have been provided with is in the format "7 Miles 100 Meters, 7 Miles 200m" etc.

What's the best way to do this?

You should convert the distances to meters or miles. I made a small example where all the distances are converted to meters. You could also add a hovertool which shows the original distance (combination miles/meters).

import pandas as pd
from bokeh.io import show
from bokeh.models import ColumnDataSource
from bokeh.palettes import Spectral5
from bokeh.plotting import figure

data = {'day': [1, 2, 3, 4, 5], 'distance': ['7.5 Miles 100m', '7.5 Miles 200m', '7 Miles 500m', '5 Miles 300m', '8 Miles 5m'], 'color': Spectral5}
df = pd.DataFrame.from_dict(data)
#Split distance columns on spaces => distance in miles | 'miles' | distance in meters + 'm'
distancedf = df["distance"].str.split(" ", n = 2, expand = True)
#Convert miles column to floats and multiply by 1609.344 to get the distance in meters
distancedf[0] = distancedf[0].astype(float)
distancedf[0] *= 1609.344
#Remove all non numeric characters from column ('m') and convert to floats
distancedf[2].replace(regex=True,inplace=True,to_replace=r'\D',value=r'')
distancedf[2] = distancedf[2].astype(float)
#Add the sum of miles + meters to the first dataframe and use this dataframe for plotting
df['distanceinm'] = distancedf[0] + distancedf[2]

#Draw a plot
source = ColumnDataSource(df)
print(source.data)
p = figure(plot_height=250)
p.xaxis.axis_label = "Day"
p.yaxis.axis_label = "Distance in meters"
p.vbar(x='day', top='distanceinm', width=0.75, color='color', source=source)
show(p)

在此处输入图片说明

If you want to display both the distance in meters and in miles you have to add an extra axis. This can be seen in the following example:

import pandas as pd
from bokeh.io import show
from bokeh.models import ColumnDataSource
from bokeh.palettes import Spectral5
from bokeh.plotting import figure
from bokeh.models import LinearAxis, Range1d
from bokeh.transform import dodge


data = {'day': [1, 2, 3, 4, 5], 'distance': ['7.5 Miles 100m', '7.5 Miles 200m', '7 Miles 500m', '5 Miles 300m', '8 Miles 5m'], 'color': Spectral5}
df = pd.DataFrame.from_dict(data)
#Split distance columns on spaces => distance in miles | 'miles' | distance in meters + 'm'
distancedf = df["distance"].str.split(" ", n = 2, expand = True)
#Convert miles column to floats and multiply by 1609.344 to get the distance in meters
df['distanceinmiles'] = distancedf[0].astype(float)
#Remove all non numeric characters from column ('m') and convert to floats
distancedf[2].replace(regex=True,inplace=True,to_replace=r'\D',value=r'')
df['distanceinmeters'] = distancedf[2].astype(float)

#Draw a plot
source = ColumnDataSource(df)
p = figure(plot_height=500, y_range=(0, df['distanceinmiles'].max()))
p.yaxis.axis_label = "Distance in Miles"
#Add extra Y axis
p.extra_y_ranges = {'meters': Range1d(start=0, end=df['distanceinmeters'].max())}
p.add_layout(LinearAxis(y_range_name="meters", axis_label='Distance in Meters'), 'right')
p.vbar(x=dodge('day', -0.21), top='distanceinmiles', width=0.4, color='color', source=source)
p.vbar(x=dodge('day', 0.21), top='distanceinmeters', width=0.4, color='color', source=source, y_range_name="meters")
p.xaxis.axis_label = "Day"
show(p)

在此处输入图片说明

(Every first bar is the distance in miles (seen on the left Y axis) and the second bar is the distance in meters (seen on the right Y axis))

I figured it out in the end, I just converted the Miles(eg 7.5) and Meters(eg 400m) into Miles (eg 7.75miles). Then I used the tickformatter to display the specific points as meters. Thanks for the help

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM