#!/usr/bin/env python # coding: utf-8 # In[1]: import numpy as np import pandas as pd from lets_plot import * from lets_plot.mapping import as_discrete # In[2]: LetsPlot.setup_html() # #### Set `theme_gray()` as default theme. It improves plots readability. # In[3]: LetsPlot.set_theme(theme_grey()) # #### Data # In[4]: labels_df = { 'x': [0, 1, 2, 3, 4, 5, 6, 7, 8], 'y': [0, 45, 90, 135, 180, 225, 270, 315, 360], 'r_y': [360, 315, 270, 225, 180, 135, 90, 45, 0], 'l': ['l0', 'l45', 'l90', 'l135', 'l180', 'l225', 'l270', 'l315', 'l360'], 'g': ['g1', 'g1', 'g1', 'g2', 'g2', 'g2', 'g3', 'g3', 'g3'] } lollipop_df = { 'c': ['a', 'b', 'c', 'd', 'e', 'f'], 'x': [1, 2, 3, 4, 5, 6], 'y': [1, 2, 3, 4, 5, 6], } student_df = { 'subj': ['progr', 'math', 'physic', 'chemistry', 'biology'], 'subj_id': [1, 2, 3, 4, 5], 'student': ['John'] * 5, 'score': [19, 15, 18, 12, 9] } # ##### Util for `PlotSpecDebugger.kt` # In[5]: def dump_plot(plot, display=False): import json try: import clipboard except: clipboard = None from lets_plot._type_utils import standardize_dict plot_dict = standardize_dict(plot.as_dict()) plot_json = json.dumps(plot_dict, indent=2) if clipboard: clipboard.copy('') clipboard.copy(str(plot_json)) else: if display is None: display = True return plot # # Geoms # ## `geom_area()` # Line get transformed into a circle: # In[6]: p = ggplot() + geom_area(aes(x=[0, 1], y=[1, 1])) gggrid([ p, p + coord_polar() ]) # ### `flat=True` # The plot can be transformed into a radar plot by using `flat=True` and a discrete x-scale. # In[7]: p = ggplot(student_df) \ + geom_area(aes(x='subj_id', y='score'), flat=True) \ + geom_point(aes(x='subj_id', y='score')) \ labels = { 1: 'progr', 2: 'math', 3: 'physic', 4: 'chemistry', 5: 'biology' } continuous = scale_x_continuous(labels=labels) discrete = scale_x_discrete(labels=labels) gggrid([ p + continuous, p + continuous + coord_polar() + ggtitle('scale_x_continuous'), p + discrete + coord_polar() + ggtitle('scale_x_discrete'), ]) # ## `geom_segment()` # In[8]: p = ggplot() \ + geom_segment(x=0, y=0, xend=4, yend=4, arrow=arrow(), size=1) \ + geom_segment(x=8, y=0, xend=4, yend=4, arrow=arrow(), size=1) \ gggrid([ p, p + coord_polar() ]) # `size_end`/`stroke_end` precision length adjustment parameters: # In[9]: # known problem - zero-length segment because of second datapoint. # this is a temp workaround to sync stroke/stroke_end and size/size_ens domains d= { 'x': [0,1], 'y':[0,0], 'size': [8,10], 'stroke':[1,2], 'size_end':[10,0], 'stroke_end':[2,0] } p = ggplot(d, aes('x','y')) \ + geom_point(aes(size='size', stroke='stroke'), shape=21, alpha=0.5, color="red", show_legend=False) \ + geom_segment( aes(size_start='size', stroke_start='stroke',size_end='size_end', stroke_end='stroke_end'), xend=1, yend=0, size=2, arrow=arrow(ends='both', type='open', length=22, angle=30), ) \ + scale_identity(['size','size_start','size_end']) gggrid([ p, p + coord_polar(xlim=[-0.35, 1.35], ylim=[-2, 2]) # lims are only to make the figure smiling ]) # ## `geom_label()` # Regular scatter plot. # In[10]: p = ggplot(labels_df, aes(x='x', y='y', label='l')) + geom_label() gggrid([ p, p + coord_polar() + ggtitle('coord_polar()'), p + coord_polar(theta='y') + ggtitle('theta=y'), ]) # ## `geom_path()` # The transform resamples path data by converting straight segments into curves. The `flat` parameter controls this behaviour. # In[11]: p = ggplot(labels_df, aes(x='x', y='y', color='y')) + scale_color_brewer(palette='GnBu') gggrid([ p + geom_path(size=3) + coord_polar() + ggtitle('coord_polar()'), p + geom_path(size=3, flat=True) + coord_polar(theta="x") + ggtitle('coord_polar(), flat=True'), ], ncol=2) # ### Autoclose on a discrete x-scale # In[12]: ggplot(student_df) + geom_path(aes(x='subj', y='score'), flat=True) + coord_polar(ylim=[0, 20]) # ## `geom_lollipop()` # See the `Params` section for details on using the `ylim` parameters. # In[13]: p = ggplot(lollipop_df, aes('c', 'y')) + geom_lollipop() gggrid([ p, p + coord_polar(), ]) # ## `geom_bar()` # This works similarly to rects, but with the addition of tooltips. # ### `position='stack'` # In[14]: from lets_plot.mapping import as_discrete bar_df = { 'foo': [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3] } p = ggplot(bar_df) + geom_bar(aes(fill=as_discrete('foo', order=1)), size=0) gggrid([ p, p + coord_polar(theta='y') + ggtitle('position=stack, coord_polar(theta=y)'), p + coord_polar(theta='x') + ggtitle('position=stack, coord_polar(theta=x)'), ]) # ### `position='dodge'` # In[15]: p = ggplot(bar_df) + geom_bar(aes(fill=as_discrete('foo', order=1)), size=0, position='dodge') gggrid([ p, p + coord_polar(theta='y') + ggtitle('position=dodge, coord_polar(theta=y)'), p + coord_polar(theta='x') + ggtitle('position=dodge, coord_polar(theta=x)'), ]) # ### `stat='identity'` # On a continuous x-scale the first and last bars stuck. The `expand` parameter can be used to fix this. # In[16]: data = { 'x': [1, 2, 3], 'y': [5, 3, 4], } bar_id = ggplot(data) + geom_bar(aes('x', 'y'), stat='identity', width=0.8) + coord_polar() gggrid([ bar_id + ggtitle('Continuous x'), bar_id + scale_x_continuous(expand=[0, 0.1]) + ggtitle('scale_x_continuous(expand=[0, 0.1))') ]) # In[17]: bar_id + scale_x_discrete() + ggtitle('Discrete x') # ### Demo: wind rose # See: https://mesonet.cdn.columbiascanner.org/onsite/windrose/IA_ASOS/PEA/PEA_yearly.png # Data: https://mesonet.cdn.columbiascanner.org/sites/windrose.phtml?station=PEA&network=IA_ASOS # In[18]: wind_df = pd.read_csv('coord_polar_wind.csv') def is_float(x): try: float(x) except ValueError: return False return True wind_df = wind_df[wind_df.sped.apply(lambda x: is_float(x))] wind_df = wind_df[wind_df.drct.apply(lambda x: is_float(x))] wind_df['sped'] = wind_df['sped'].astype(float) wind_df['drct'] = wind_df['drct'].astype(float) wind_df = wind_df[wind_df.sped.apply(lambda x: x >= 2.0)] wind_df.head() # In[19]: # Define the speed bins bins = [2, 5, 7, 10, 15, 20, float('inf')] bin_ids = list(range(6)) wind_df['speed_group'] = pd.cut(wind_df['sped'], bins=bins, labels=bin_ids, right=False) # Group by 'drct' and 'speed_group', and count the occurrences grouped_counts = wind_df.groupby(['drct', 'speed_group']).size().reset_index(name='count') # Calculate the total number of observations in the dataset total_observations = wind_df.shape[0] # Calculate the percentage of each speed group within each direction relative to the total number of observations grouped_counts['percentage_of_total'] = (grouped_counts['count'] / total_observations) * 100 # In[20]: from lets_plot.mapping import as_discrete ggplot(grouped_counts) \ + geom_bar(aes('drct', 'percentage_of_total', fill=as_discrete('speed_group', order=1)), stat='identity', size=0, width=0.8) \ + scale_fill_manual( name='Wind Speed:', breaks={'2 - 4.9': 0, '5 - 6.9': 1, '7 - 9.9': 2, '10 - 14.9': 3, '15 - 19.9': 4, '20+': 5}, values=['#002bff', '#03d3f8', '#7afe81', '#fde609', '#ff4404', '#780200'], ) \ + scale_x_continuous( expand=[0, 1], breaks={'N': 360, 'NE': 45, 'E': 90, 'SE': 135, 'S': 180, 'SW': 225, 'W': 270, 'NW': 315}, ) \ + ggsize(800, 800) \ + coord_polar(ylim=[-1, None], start=(3.14 * 2) / 36 / 2) \ + theme_minimal2() \ + theme( panel_grid_ontop=True, axis_ontop=True, panel_grid=element_line(color='#A0A0A0') ) # ## `geom_hline()`/`geom_vline()` # In[21]: p = ggplot() \ + geom_hline(yintercept=5, color='red') \ + geom_hline(yintercept=10, color='green') \ + geom_hline(yintercept=15, color='blue') \ + geom_hline(yintercept=20, color='orange') \ + geom_vline(xintercept=10, color='pink') \ + geom_vline(xintercept=20, color='magenta') \ + geom_vline(xintercept=30, color='dark_green') \ + xlim(0, 30)\ + ylim(0, 20) gggrid([p, p + coord_polar()]) # ## `geom_tile()` # In[22]: x = list(range(24)) d1 = list(np.interp(x, [0, 8, 14, 18, 23], [3, 12, 18, 8, 2])) d2 = list(np.interp(x, [0, 8, 14, 18, 23], [2, 7, 11, 5, 0])) d3 = list(np.interp(x, [0, 8, 14, 18, 23], [0, 11, 15, 13, 8])) d4 = list(np.interp(x, [0, 8, 14, 18, 23], [8, 7, 11, 5, 2])) d5 = list(np.interp(x, [0, 8, 14, 18, 23], [2, 12, 20, 15, 12])) d6 = list(np.interp(x, [0, 8, 14, 18, 23], [12, 14, 22, 19, 15])) d7 = list(np.interp(x, [0, 8, 14, 18, 23], [15, 13, 26, 22, 11])) temp = d1 + d2 + d3 + d4 + d5 + d6 + d7 day = ([1] * 24) + ([2] * 24) + ([3] * 24) + ([4] * 24) + ([5] * 24) + ([6] * 24) + ([7] * 24) df = pd.DataFrame({ "time": [i for i in range(24)] * 7, "day": day, "temp": temp }) p = ggplot(df) \ + geom_tile(aes(x='time', y='day', fill='temp'), tooltips=layer_tooltips().format('^x', '{.1d}:00')) \ + scale_fill_viridis() \ + scale_x_continuous(format='{.1d}:00') \ + scale_y_discrete(breaks={ 'Mon': 1, 'Tue': 2, 'Wen': 3, 'Thu': 4, 'Fri': 5, 'Sat': 6, 'Sun': 7 }) gggrid([ p, p \ + theme(panel_inset=[0, 20, 0, 20]) + coord_polar(ylim=[-2, None], start=(-3.14 * 2) / 24 / 2) # ylim=-2 to make the hole, start to align ticks vertically ]) + ggsize(1200, 600) # ## `geom_rect()` # ### Stacked bars # are transformed into a pie chart # In[23]: c1 = '#66c2a5' c2 = '#fc8d62' c3 = '#8da0cb' p = ggplot() \ + geom_rect(xmin=0, xmax=5, ymin=0, ymax=7, fill=c1, size=0) \ + geom_rect(xmin=0, xmax=5, ymin=7, ymax=11, fill=c2, size=0) \ + geom_rect(xmin=0, xmax=5, ymin=11, ymax=14, fill=c3, size=0) gggrid([ p, p + coord_polar() + ggtitle('coord_polar()'), p + coord_polar(theta='y') + ggtitle('coord_polar(theta=y)'), ]).show() gggrid([ p + coord_polar(theta='y', direction=-1) + ggtitle('coord_polar(theta=y, dir=-1)'), p + coord_polar(theta='y', direction=-1, start=3.14/2) + ggtitle('coord_polar(theta=y, dir=-1, start=PI/2)'), ]).show() # ### Dodged bars # In[24]: p = ggplot() \ + geom_rect(xmin=0, xmax=1, ymin=0, ymax=7, fill=c1, size=0) \ + geom_rect(xmin=1, xmax=2, ymin=0, ymax=4, fill=c2, size=0) \ + geom_rect(xmin=2, xmax=3, ymin=0, ymax=3, fill=c3, size=0) \ gggrid([ p, p + coord_polar(theta='y') + ggtitle('coord_polar(theta=y)'), p + coord_polar(theta='x') + ggtitle('coord_polar(theta=x)'), ]) # ### Horizontal bars # In[25]: p = ggplot() \ + geom_rect(ymin=0, ymax=1, xmin=0, xmax=7, fill=c1, size=0) \ + geom_rect(ymin=1, ymax=2, xmin=0, xmax=4, fill=c2, size=0) \ + geom_rect(ymin=2, ymax=3, xmin=0, xmax=3, fill=c3, size=0) \ gggrid([ p, p + coord_polar(theta='y') + ggtitle('coord_polar(theta=y)'), p + coord_polar(theta='x') + ggtitle('coord_polar(theta=x)'), ]) # # Params # In[26]: p = ggplot(labels_df, aes(x='x', y='y', color='y')) + geom_path(size=3, show_legend=False) + scale_color_brewer(palette='GnBu') p + coord_polar() + ggtitle('Default plot with coord_polar()') # ### `transform_bkgr` # # When using the `transform_bkgr` parameter, the panel is not transformed into a circle, but remains a rectangle. This behaviour is similar to `ggplot2`. # In[27]: p + coord_polar(transform_bkgr=False) + ggtitle('coord_polar(transform_bkgr=False)') # ### `direction` # In[28]: p + coord_polar(direction=-1) + ggtitle('coord_polar(direction=-1)') # ### `start` # In[29]: gggrid([ p + coord_polar(start=3.14 / 2) + ggtitle('start=PI/2'), p + coord_polar(start=-3.14 / 2) + ggtitle('start=-PI/2'), ]) # ### `direction` + `start` # In[30]: gggrid([ p + coord_polar(start=3.14 / 2, direction=-1) + ggtitle('dir=-1, start=PI/2'), p + coord_polar(start=-3.14 / 2, direction=-1) + ggtitle('dir=-1, start=-PI/2'), ]) # ### `xlim` and `ylim` # The `xlim` parameter can be used to prevent overlap between the first and last values. # The `ylim` parameter can be used to shift data away from the centre or the outer circle. # # To prevent overlap between `6` and `1`, we adjust the `xlim` to `[None, 7]` while keeping the default minimum limit as it is not relevant. # In addition, we change `ylim` to `[None, 6.5]` to prevent the lollipop's top from overlapping with the outer circle. # In[31]: p = ggplot(lollipop_df) \ + geom_lollipop(aes(x='x', y='y')) gggrid([ p + coord_polar(), p + coord_polar(xlim=[None, 7], ylim=[None, 6.5]) ]) # # Scales # Interaction between scales and polar coordinate system. # In[32]: pie = ggplot() \ + geom_rect(xmin=0, xmax=1, ymin=0, ymax=7, fill='red', size=0) \ + geom_rect(xmin=1, xmax=2, ymin=0, ymax=4, fill='blue', size=0) \ + geom_rect(xmin=2, xmax=3, ymin=0, ymax=3, fill='green', size=0) \ + coord_polar() sticks_df = { 'x': [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5], 'y': [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6], 'g': [5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0] } sticks = ggplot(sticks_df) + geom_path(aes(x='x', y='y', group='g', size='g')) + coord_polar() # ## Limit # The `limits` parameter sets the lower and upper limits individually, but expects absolute values. # `x=[None, 6]` limit to make the first and last elements not overlap. # `y=[-2, 7]` limit to make a medium sized centre hole and a small outer buffer (with a length of 1). # In[33]: gggrid([ sticks + ggtitle('No limits'), sticks + lims(x=[None, 6], y=[-2, 7]) + ggtitle('lims(x=[None, 6], y=[-2, 7])'), ]) # ## Discrete x-scale # # If the x-scale is discrete, the coordinate system will automatically adjust domain so that the first and last values don't overlap. # In[34]: gggrid([ sticks + ggtitle('Continuous'), sticks + scale_x_discrete() + ggtitle('scale_x_discrete()') ]) # ## clip-path # # Segments should not get rendered outside the panel boundaries. # In[35]: gggrid([ sticks, sticks + coord_polar(ylim=[0, 1.5]) ]) # ## Expand # By default `coord_polar()` resets the expansion to zero, but it can still be set explicitly. # Horizontal non-zero expand will produce a gap between first and last sectors, so the plot will never become a circle. # Vertical non-zero expand creates a central hole (expand for the bottom of the domain) and a buffer between the plot and the axis (expand for the top of the domain). # # `expand` is symmetric, so it can't be used to adjust only the bottom or only the top. # In[36]: gggrid([ sticks + ggtitle('No expand'), sticks \ + scale_x_continuous(expand=[0, 2.5]) \ + scale_y_continuous(expand=[0, 2]) \ + ggtitle('scale_XY_continuous(expand=...)'), ]) # ## `scale_y_log10()` # Log-scale works fine. # In[37]: d = { 'x': [1, 2, 3, 4, 5, 6, 7, 8], 'y': [1, 10, 100, 1_000, 10_000, 100_000, 1_000_000, 10_000_000], } p = ggplot(d) + geom_path(aes(x='x', y='y'), flat=True) p gggrid([ p, p + coord_polar(), p + scale_y_log10(), p + scale_y_log10(format='.1~e') + coord_polar(), ], ncol=2) # # Theme # In[38]: p = ggplot(labels_df, aes(x='x', y='y', color='y')) + scale_color_brewer(palette='GnBu') + geom_path(size=3) polar_p = p + coord_polar() # ## Themes list # In[39]: gggrid([ p, polar_p + theme_minimal2() + ggtitle('theme_minimal2()'), polar_p + theme_bw() + ggtitle('theme_bw()'), polar_p + theme_classic() + ggtitle('theme_classic()'), polar_p + theme_grey() + ggtitle('theme_grey()'), polar_p + theme_light() + ggtitle('theme_light()'), polar_p + theme_minimal() + ggtitle('theme_minimal()'), polar_p + theme_none() + ggtitle('theme_none()'), polar_p + theme_void() + ggtitle('theme_void()'), ], ncol=3) # ## Axis configuration # In[40]: p_tmp = p + theme( axis_line_y=element_line(color='red', size=2), axis_line_x=element_line(color='blue', size=2), axis_ticks_length_y=5, axis_ticks_length_x=10, axis_ticks_y=element_line(size=5, color='red'), axis_ticks_x=element_line(size=3, color='blue'), axis_text_x=element_text(color='blue'), axis_text_y=element_text(color='red'), ) gggrid([ p_tmp, p_tmp + coord_polar() ]) # ## panel_inset # The `panel_inset` parameter can be used to create space between the axis and the panel content: # In[41]: p_themed = p_tmp p_themed += theme( plot_background=element_rect(fill='pink'), panel_background=element_rect(fill='grey'), panel_border=element_rect(color='green', size=1), panel_inset=[10, 10, 10, 10], ) gggrid([ p_themed, p_themed + coord_polar() ]) # # Issues # ## 1. Ticks overlapping # In[42]: data = { 'x': ['txt 1', 'txt 2', 'txt 3', 'txt 4'], 'y': [1, 2, 3, 4], } ggplot(data, aes('x', 'y')) + geom_point() + coord_polar() # ## 2. Marginal plot (what to do with them at all) # In[43]: ggplot(labels_df, aes(x='x', y='y', color='y')) + scale_color_brewer(palette='GnBu') \ + geom_path(size=3, show_legend=False) \ + ggmarginal('trlb', layer=geom_line(color='black', show_legend=False)) \ + coord_polar() \ + theme( axis_line_y=element_line(color='red', size=2), axis_line_x=element_line(color='blue', size=2), axis_ticks_length_y=5, axis_ticks_length_x=10, axis_ticks_y=element_line(size=5, color='red'), axis_ticks_x=element_line(size=3, color='blue'), axis_text_x=element_text(color='blue'), axis_text_y=element_text(color='red'), panel_border=element_rect(color='magenta', size=1), panel_background=element_rect(fill='orange'), panel_inset=[10, 10, 10, 10], plot_margin=10, plot_background=element_rect(fill='cyan'), ) # In[44]: bar_df = { 'foo': [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3] } p = ggplot(bar_df) + geom_bar(aes(fill=as_discrete('foo', order=1)), size=0) p = ggplot(bar_df) + geom_bar(aes(fill=as_discrete('foo', order=1)), size=0, position='dodge') gggrid([ p, p + coord_polar(theta='y') + ggtitle('position=dodge, coord_polar(theta=y)'), p + coord_polar(theta='x') + ggtitle('position=dodge, coord_polar(theta=x)'), ]) # # Regressions # ## Axis and grid alignment still works in all cases: # - coord_flip # - title # - top/bottom/left/right # - marginal # - facet # In[45]: p = ggplot(labels_df, aes(x='x', y='y', color='y')) + geom_path(size=3) + scale_color_brewer(palette='GnBu') + theme_light() default = p + ggtitle('Default') both = p + scale_x_continuous(position='both') + scale_y_continuous(position='both') + ggtitle('Both') flip = p + coord_flip() + ggtitle('coord_flip()') flip_both = p + scale_x_continuous(position='both') + scale_y_continuous(position='both') + coord_flip() + ggtitle('both + coord_flip()') facet = p + facet_grid(x='g') + ggtitle('Facet') facet_both = both + facet_grid(x='g') + ggtitle('Facet Both') facet_flip = flip + facet_grid(x='g') + ggtitle('Facet Flip') facet_flip_both = flip_both + facet_grid(x='g') + ggtitle('Facet Flip Both') g = gggrid([ default, both, flip, flip_both, facet, facet_both, facet_flip, facet_flip_both ], ncol=1) g # In[46]: both + coord_polar() # Single plot review: # In[47]: p = ggplot(labels_df, aes(x='x', y='y', label='l')) + geom_label() p_rect_stack = ggplot() \ + geom_rect(xmin=0, xmax=5, ymin=0, ymax=7, fill=c1, size=0) \ + geom_rect(xmin=0, xmax=5, ymin=7, ymax=11, fill=c2, size=0) \ + geom_rect(xmin=0, xmax=5, ymin=11, ymax=14, fill=c3, size=0) \ p_rect_dodge = ggplot() \ + geom_rect(xmin=0, xmax=1, ymin=0, ymax=7, fill=c1, size=0) \ + geom_rect(xmin=1, xmax=2, ymin=0, ymax=4, fill=c2, size=0) \ + geom_rect(xmin=2, xmax=3, ymin=0, ymax=3, fill=c3, size=0) \ gggrid([ p_rect_dodge, p_rect_dodge + coord_polar(theta='y') + ggtitle('coord_polar(theta=y)'), p_rect_dodge + coord_polar(theta='x') + ggtitle('coord_polar(theta=x)'), ]) from lets_plot.mapping import as_discrete bar_df = { 'foo': [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3] } p_bar_stack = ggplot(bar_df) + geom_bar(aes(fill=as_discrete('foo', order=1)), size=0) p_bar_dodge = ggplot(bar_df) + geom_bar(aes(fill=as_discrete('foo', order=1)), size=0, position='dodge') # lollipop p_lollipop = ggplot(lollipop_df, aes('x', 'y')) + geom_lollipop() + coord_polar(xlim=[1, 7]) # radar p_radar = ggplot(student_df) \ + geom_path(aes(x='subj', y='score', color='student'), flat=True) \ + geom_point(aes(x='subj', y='score', color='student'))\ + coord_polar(ylim=[0, 20]) gggrid([ p + coord_polar() + ggtitle('coord_polar()'), p + coord_polar(theta='y') + ggtitle('theta=y'), None, p_rect_stack + coord_polar(theta='y') + ggtitle('coord_polar(theta=y)'), p_rect_stack + coord_polar(theta='y', direction=-1) + ggtitle('coord_polar(theta=y, dir=-1)'), p_rect_stack + coord_polar(theta='x') + ggtitle('coord_polar(theta=x)'), p_rect_dodge, p_rect_dodge + coord_polar(theta='y') + ggtitle('coord_polar(theta=y)'), p_rect_dodge + coord_polar(theta='x') + ggtitle('coord_polar(theta=x)'), p_bar_stack, p_bar_stack + coord_polar(theta='y') + ggtitle('position=stack, coord_polar(theta=y)'), p_bar_stack + coord_polar(theta='x') + ggtitle('position=stack, coord_polar(theta=x)'), p_bar_dodge, p_bar_dodge + coord_polar(theta='y') + ggtitle('position=dodge, coord_polar(theta=y)'), p_bar_dodge + coord_polar(theta='x') + ggtitle('position=dodge, coord_polar(theta=x)'), p_lollipop, p_radar ], ncol=3) # # Sandbox # In[48]: mpg = pd.read_csv('https://raw.githubusercontent.com/JetBrains/lets-plot-docs/master/data/mpg.csv') mpg # In[49]: mpg2 = mpg.copy() mpg2['name'] = mpg2.apply(lambda x: f"{x['model']}-{x['displ']}-{x['year']}-{x['trans']}-{x['drv']}", axis=1) mpg2 # In[50]: ggplot(mpg) + geom_bar(aes(x='model', y='cty', fill='cty'), stat='identity', position='dodge') + scale_fill_gradient(low='red', high='white', limits=(5,40)) #+ theme_void() # In[51]: p_default = ggplot(mpg) \ + geom_bar(aes(x='model', y='cty', fill='cty'), stat='identity', position='dodge') \ + scale_fill_gradient(low='red', high='white', limits=(5,40)) \ + ggsize(800, 400) \ + ggtitle('default') \ + coord_polar() p_default.show() inset = [20, 140, 30, 120] p_adjusted = ggplot(mpg) \ + geom_bar(aes(x='model', y='cty', fill='cty'), stat='identity', position='dodge') \ + scale_fill_gradient(low='red', high='white', limits=(5,40)) \ + theme( axis_text_x=element_text(angle=10), panel_inset=inset ) \ + ggsize(900, 500) \ + ggtitle('panel_inset=' + str(inset)) \ + coord_polar() p_adjusted.show() # In[52]: p = ggplot(labels_df, aes(x='x', y='y', label='l')) + geom_point(alpha=0.3, color='red') + geom_text() gggrid([ p + coord_polar(theta='x'), p + coord_polar(theta='y'), ]) # In[53]: p = ggplot() + geom_density2df(aes(x=[0, 1], y=[0, 1], fill='..level..'), bins=6, show_legend=False) gggrid([ p, p + coord_polar() ]) # In[54]: p = ggplot() + geom_density2df(aes(x=[0, 1], y=[0, 1], fill='..level..'), bins=2, show_legend=False) gggrid([ p, p + coord_polar() ]) # In[55]: p = ggplot() + geom_density2df(aes(x=[1, 0, 0, 1], y=[1, 0, 1, 0], fill='..level..'), bins=2, show_legend=False) gggrid([ p, p + coord_polar() ]) # In[56]: import numpy as np from lets_plot import * LetsPlot.setup_html() n = 1000 np.random.seed(42) x = np.random.normal(size=n) y = np.random.normal(size=n) p = ggplot({'x': x, 'y': y}, aes(x='x', y='y')) + \ geom_density2df(aes(fill='..group..'), show_legend=False) + \ scale_fill_brewer(type='seq', palette='GnBu', direction=-1) gggrid([ p, p + coord_polar() ]) # In[ ]: