6969kPa = ureg .kilopascal
7070MPa = ureg .megapascal
7171GPa = ureg .gigapascal
72+ percent = ureg .percent
73+ pct = ureg .pct
7274
7375unit_list = ['inch' , 'feet' , 'ft' , 'mi' , 'ozf' , 'lbf' , 'lbm' , 'kip' , 'ton' , 'tonf' , 'plf' , 'klf' , 'psi' , 'psf' ,
7476 'ksi' , 'ksf' , 'pcf' , 'kcf' , 'lbin' , 'lbft' , 'kipin' , 'kipft' , 'kin' , 'kft' , 'mph' ,
7577 'rpm' , 'Hz' , 'deg' , 'rad' , 'sec' , 'minute' , 'hr' , 'gal' , 'degF' , 'degC' , 'mm' , 'cm' , 'm' , 'km' , 'N' , 'kN' , 'kgf' , 'tonne' , 'tonnef' , 'Pa' ,
76- 'kPa' , 'MPa' , 'GPa' ]
78+ 'kPa' , 'MPa' , 'GPa' , 'percent' , 'pct' ]
7779
7880#%%
7981@register_cell_magic
@@ -167,6 +169,8 @@ def sync_namespaces(local_ns):
167169 local_ns ['GPa' ] = ureg .gigapascal
168170 local_ns ['tonne' ] = ureg .tonne
169171 local_ns ['tonnef' ] = ureg .tonnef
172+ local_ns ['percent' ] = ureg .percent
173+ local_ns ['pct' ] = ureg .pct
170174
171175 # Provide the IPython console with access to the `funit` method
172176 local_ns ['funit' ] = funit
@@ -209,6 +213,10 @@ def process_line(calc_line, local_ns):
209213 equation = equation .replace ('^prime' , '_prime' )
210214 equation = equation .replace ('^' , '**' )
211215 equation = equation .replace ('lambda' , 'lamb' )
216+
217+ # Convert percentage symbols to percent units
218+ # Match % symbols that follow numbers/variables (but not in strings)
219+ equation = re .sub (r'(\d+(?:\.\d+)?)\s*%' , r'\1*percent' , equation )
212220
213221 # Resolve prime symbols in the variable before we compare it to the equation, which has already had them resolved
214222 variable = variable .replace ('^prime' , '_prime' )
@@ -479,15 +487,20 @@ def replace_string(match):
479487
480488 # Provide a space before any units
481489 text = text .replace ('*inch' , ' \\ in' )
490+
491+ # Handle percent specially - use % symbol instead of word
492+ text = text .replace ('*percent' , '\\ %' )
493+ text = text .replace ('*pct' , '\\ %' )
482494 for unit in unit_list :
483- text = text .replace ('*' + unit , ' \\ ' + unit )
495+ if unit not in ['percent' , 'pct' ]: # Skip percent as we already handled it
496+ text = text .replace ('*' + unit , ' \\ ' + unit )
484497
485498 # Replace multiplication symbols in front of numbers with a multiplication dot
486499 for i in range (10 ):
487500 text = text .replace ('*' + str (i ), '\\ cdot{}' + str (i ))
488501
489- # Remove all other multiplication symbols
490- text = text .replace ('*' , '' )
502+ # Convert remaining multiplication symbols to centered dots for better readability
503+ text = text .replace ('*' , '\\ cdot{} ' )
491504
492505 # Return the Latex text
493506 return text
@@ -688,6 +701,9 @@ def funit(value, precision=None):
688701 latex_value = str (round (value , precision ))
689702 else :
690703 latex_value = str (value )
704+
705+ # Replace pct unit with % symbol early
706+ latex_value = latex_value .replace ('pct' , '%' )
691707
692708 # Step through each character in the value
693709 for i , char in enumerate (latex_value ):
@@ -700,7 +716,10 @@ def funit(value, precision=None):
700716
701717 # The round function tags on a .0 after it rounds floats. It doesn't do it to integers. Correct this.
702718 if precision == 0 :
703- latex_value = latex_value .replace ('.0' , '' )
719+ latex_value = latex_value .replace ('.0' , '' )
720+
721+ # Escape the % symbol for LaTeX
722+ latex_value = latex_value .replace ('%' , '\\ %' )
704723
705724 # Return the formatted value
706725 return latex_value
0 commit comments